KQ-868 · PIN/MESSAGE

Pin Message

A thread with a bar at the top and a flight between them. Pressing a message's pin measures the gap between that row and the bar's floor at the moment of the press, and the copy enters the bar from exactly there, riding y to zero on glide, so it reads as lifted out of the thread rather than faded into a list; unpinning sends it back down the same distance on the exit ease. The bar's height comes from a ResizeObserver bound to its content, so an empty bar occupies nothing, and at the cap the remaining pin controls go aria-disabled with names that say why rather than leaving the tab order.

KQ-868 · PIN/MESSAGE

Pinned1 of 3

  1. Ines Moreau14:38
    Coldbrook depot closes Thursday from noon. Nothing leaves the yard after eleven.
  2. Marta Ferreira14:52
    Morning run can take the Basinworks pallets instead. Two, both labelled.
  3. Rui Baptista15:11
    Dock three is free from nine, and the loader is booked until half past.
  4. Ines Moreau15:24
    Waylight Pay reference for the yard fee is 4471-CB. Put it on the sheet.

1 of 3 pinned · last pinned Ines 14:38

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/pin-message

Props

messages
PinnedMessage[]
default
The thread, oldest first; each carries an id, author, text and formatted time.
value / defaultValue
string[]
default []
Controlled or initial pinned ids, most recently pinned first.
onValueChange
(ids: string[]) => void
default
Fires from a pin or an unpin with the next pinned set.
onPinChange
(id: string, pinned: boolean) => void
default
Fires with the message that changed and its new state.
onJump
(id: string) => void
default
Fires when a bar row sends focus down to its message.
maxPinned
number
default 3
How many the bar holds before the remaining pin controls refuse.
label
string
default "Thread"
Names the thread list for assistive technology.
barLabel
string
default "Pinned"
Names the pinned bar and heads it.