KQ-876 · TYPING/CLUSTER
Typing Cluster
One typer gets a row of their own, and so does a second; the moment a third starts the rows merge into one cluster, every disc keeping its own element and sliding into the overlapped stack on glide. The merged row's name slot rotates through the typers on snap, and pressing it spreads the stack back into the named rows — Escape re-merges without moving focus. The whole strip lives in a ResizeObserver-measured height, so one row, three rows and none of them are all the same glide.
KQ-876 · TYPING/CLUSTER
- Marta Vieira is typing
- Rui Sequeira is typing
2 typing · Marta, Rui
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/typing-cluster
Props
- typing
- string[]
- default []
- Who is typing, in the order they started. Empty collapses the strip.
- mergeAt
- number
- default 3
- Typers needed before the separate rows merge into one cluster.
- rotateMs
- number
- default 2200
- Milliseconds each name holds the merged row's slot.
- maxFaces
- number
- default 4
- Discs drawn in the stack before the rest become a rolling +N.
- expanded / defaultExpanded
- boolean
- default false
- Controlled or initial spread state of the merged cluster.
- onExpandedChange
- (expanded: boolean) => void
- default —
- Fires when the cluster is spread or re-merged.
- onFocusNameChange
- (name: string | null) => void
- default —
- Fires when the rotating slot lands on a different name; null when nobody types.
- label
- string
- default —
- Names the strip for assistive technology.
| Prop | Type | Default | Description |
|---|---|---|---|
| typing | string[] | [] | Who is typing, in the order they started. Empty collapses the strip. |
| mergeAt | number | 3 | Typers needed before the separate rows merge into one cluster. |
| rotateMs | number | 2200 | Milliseconds each name holds the merged row's slot. |
| maxFaces | number | 4 | Discs drawn in the stack before the rest become a rolling +N. |
| expanded / defaultExpanded | boolean | false | Controlled or initial spread state of the merged cluster. |
| onExpandedChange | (expanded: boolean) => void | — | Fires when the cluster is spread or re-merged. |
| onFocusNameChange | (name: string | null) => void | — | Fires when the rotating slot lands on a different name; null when nobody types. |
| label | string | — | Names the strip for assistive technology. |