KQ-2055 · WIDGET/THREAD
Widget Thread
An assistant whose replies are small live controls — a quantity stepper, a compare table, a slot picker, a confirm card — each assembling out of a skeleton block by block, every block rising a nudge on springs.snap in a cascade. Whatever is chosen inside a widget lifts out and becomes the next sent message: a copy of the chosen thing travels to the new bubble on springs.glide, its box morphing from the control to the bubble as its fill warms to the bubble colour, while the widget fades to a read-only record with the choice ticked on springs.flick. Each widget is one tab stop with its own keyboard path (radiogroup, spinbutton, roving table buttons, roving confirm buttons), so Tab leaves it for the composer, where typing an option's name answers it too.
1 of 4 chosen · comparing rooms
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/widget-thread
Props
- turns
- WidgetTurn[]
- default defaultWidgetTurns
- The assistant's script; each turn's text and widget may be functions of the choices so far.
- request
- string
- default "Book a room for the Gaugeworks review on Thursday."
- The visitor's opening message.
- defaultValue
- WidgetChoices
- default {}
- Choices already made; the thread replays them and opens at the first open widget.
- onValueChange
- (choices: WidgetChoices) => void
- default —
- Fires from the choice that changed them, with every choice so far.
- onWidgetSubmit
- (widgetId: string, choice: WidgetChoice, choices: WidgetChoices) => void
- default —
- A widget was used.
- onSend
- (text: string) => void
- default —
- Free text was sent from the composer.
- onRetry
- (widgetId: string | null) => void
- default —
- Refresh on an expired widget, or Try again after a failed load (null).
- widgetChrome
- "card" | "tinted" | "plain"
- default "card"
- Bordered widget cards, accent-washed panels, or controls set straight into the reply.
- density
- "compact" | "regular" | "roomy"
- default "regular"
- Type and spacing.
- accent
- string
- default "var(--accent-bright)"
- Your bubbles, chosen states and the flight — any CSS colour.
- now
- number
- default defaultWidgetNow
- The current time in ms; widgets with expiresIn expire against it.
- typingDelay
- number
- default 520
- Milliseconds the assistant types before a reply assembles.
- assistant
- string
- default "Coldbrook Desk"
- Who is answering.
- title
- string
- default "Book a room"
- The surface's heading and accessible name.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the thread has loaded.
- height
- number
- default 520
- Height of the surface in px; the thread scrolls inside it.
- disabled
- boolean
- default false
- Read only: nothing can be chosen or sent.
- className
- string
- default —
- Classes for the surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| turns | WidgetTurn[] | defaultWidgetTurns | The assistant's script; each turn's text and widget may be functions of the choices so far. |
| request | string | "Book a room for the Gaugeworks review on Thursday." | The visitor's opening message. |
| defaultValue | WidgetChoices | {} | Choices already made; the thread replays them and opens at the first open widget. |
| onValueChange | (choices: WidgetChoices) => void | — | Fires from the choice that changed them, with every choice so far. |
| onWidgetSubmit | (widgetId: string, choice: WidgetChoice, choices: WidgetChoices) => void | — | A widget was used. |
| onSend | (text: string) => void | — | Free text was sent from the composer. |
| onRetry | (widgetId: string | null) => void | — | Refresh on an expired widget, or Try again after a failed load (null). |
| widgetChrome | "card" | "tinted" | "plain" | "card" | Bordered widget cards, accent-washed panels, or controls set straight into the reply. |
| density | "compact" | "regular" | "roomy" | "regular" | Type and spacing. |
| accent | string | "var(--accent-bright)" | Your bubbles, chosen states and the flight — any CSS colour. |
| now | number | defaultWidgetNow | The current time in ms; widgets with expiresIn expire against it. |
| typingDelay | number | 520 | Milliseconds the assistant types before a reply assembles. |
| assistant | string | "Coldbrook Desk" | Who is answering. |
| title | string | "Book a room" | The surface's heading and accessible name. |
| status | "ready" | "loading" | "error" | "ready" | Whether the thread has loaded. |
| height | number | 520 | Height of the surface in px; the thread scrolls inside it. |
| disabled | boolean | false | Read only: nothing can be chosen or sent. |
| className | string | — | Classes for the surface. |