AI chat
Chat thread
Compound component: `ChatThread`, `ChatThread.Message`, `ChatThread.Empty`.
Import
import { ChatThread, ChatThreadEmpty } from '@the_viveksingh/vivek-ui'A scrolling thread
Sticks to the bottom as messages arrive, but stops sticking once the reader scrolls up - which is what keeps it from yanking them away from what they were reading.
<ChatThread
style={{ height: '20rem' }}
messages={messages.map((message) => ({
id: message.id,
role: message.role,
name: message.name,
content: message.text,
timestamp: message.at,
status: message.status,
}))}
/>While a reply streams
loading appends a typing indicator and announces it politely.
<ChatThread messages={messages} loading loadingLabel="Assistant is typing" />Empty
Import ChatThreadEmpty by name rather than reaching for ChatThread.Empty. Dot access on a Client Component reads as undefined from a Server Component, so the named export is the one that works in both places.
import { ChatThread, ChatThreadEmpty } from '@the_viveksingh/vivek-ui'
<ChatThread
emptyState={<ChatThreadEmpty>No messages yet. Ask anything.</ChatThreadEmpty>}
/>Props
Generated from the package's own type declarations, so this table cannot drift from the code.
| Prop | Type | Default | Description |
|---|---|---|---|
messages | ChatThreadMessage[] | — | Data-driven transcript. When omitted, `children` is rendered instead. |
autoScroll | boolean | — | Keep the newest content in view. Defaults to `true`. It sticks to the bottom only while the user is already at the bottom — scrolling up to re-read something is never interrupted. See the note on the component. |
loading | boolean | — | Show the typing indicator under the transcript. |
loadingLabel | string | — | Label for that indicator. Defaults to `TypingIndicator`'s own. |
emptyState | ReactNode | — | Rendered instead of an empty transcript. |
label | string | — | Accessible name of the log region. Defaults to `Conversation`. |
stickThreshold | number | — | How close to the bottom, in px, still counts as "at the bottom". Defaults to 48 - enough to survive sub-pixel rounding and a half-visible line. |
Every remaining prop is spread onto the root element, so all standard HTML and ARIA attributes work. className and style are merged with the library's own, never replaced, and the ref forwards to the root DOM node.
Exports
ChatThreadChatThreadEmptyRendering
ChatThread declares 'use client' because it needs state, effects or event handlers. Importing it into a Server Component creates a client boundary at this component — everything above it stays on the server.