Conversation
Top-level chat shell that sticks to the latest turn, with empty, scroll, streaming, and download controls.
Conversation is the scroll shell around a chat transcript. It sticks to the latest turn while content grows, shows a jump-to-latest control when the reader scrolls away, and can export the thread as Markdown. Pair it with Message, Bubble, Marker, and Attachment for every AI turn state.
Installation
pnpm dlx cubix@latest add conversation --base ariaUsage
import {
Conversation,
ConversationContent,
ConversationEmptyState,
ConversationScrollButton,
ConversationDownload,
} from "@/components/cubix/conversation"<Conversation>
<ConversationContent>
<Message>...</Message>
</ConversationContent>
<ConversationDownload messages={messages} />
<ConversationScrollButton />
</Conversation>Note: Conversation owns the viewport - stick-to-bottom, empty state, scroll, and download. Message owns each row inside it.
Composition
Conversation
├── ConversationContent
│ ├── ConversationEmptyState
│ ├── Marker…
│ ├── MessageGroup…
│ └── Message…
├── ConversationDownload
└── ConversationScrollButtonFeatures
- Sticks to the bottom as new messages arrive
- Smooth resize follow while streamed content grows
- Scroll button when the reader leaves the latest turn
- Optional Markdown download of the thread
- Empty state for cold starts
- Hosts typing, generating, streaming, stopped, failed, attachment, and action rows via Message parts
Empty state
Render ConversationEmptyState when the thread has no messages yet.
Scroll button
Scroll up in the preview to reveal ConversationScrollButton.
Download
Use ConversationDownload to export the thread as Markdown. Pass plain { role, text } messages - no AI SDK types required.
Typing
Show a peer typing indicator with Marker while the shell stays stuck to the bottom.
Generating
Before the first token arrives, render a spinner status row inside the transcript.
Streaming
Grow a single assistant bubble as tokens arrive. Offer Stop while streaming, then switch to copy and feedback actions when done.
Stopped
When the user stops generation mid-reply, keep the partial text and offer a continue control.
Failed turns
Cover both failed user sends and failed model generations with retry actions.
Attachments
Nest Attachment under MessageContent for files sent by the user or returned by the assistant.
Response actions
After a completed assistant turn, expose copy, feedback, and regenerate in the message footer.
Message groups
Nest MessageGroup for stacked turns from the same sender. Use a separator marker for day breaks. Empty MessageAvatar keeps earlier bubbles aligned with the final avatar.
Live thread
As whole messages append, the shell follows the latest turn. Scroll away to reveal the jump button.
API Reference
Conversation
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional classes for the conversation root. |
| initial | "smooth" | "instant" | false | "smooth" | Scroll behavior when the conversation first mounts. |
| resize | "smooth" | "instant" | false | "smooth" | Scroll behavior when content size changes. |
ConversationContent
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional classes for the scrollable content area. |
ConversationEmptyState
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | "No messages yet" | Empty-state heading. |
| description | string | "Start a conversation to see messages here." | Supporting empty-state copy. |
| icon | React.ReactNode | - | Optional icon above the empty-state title. |
| children | React.ReactNode | - | Replace the default empty layout with custom content. |
ConversationScrollButton
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional classes for the jump-to-latest button. Hidden while at the bottom. |
ConversationDownload
| Prop | Type | Default | Description |
|---|---|---|---|
| messages | ConversationMessage[] | - | Messages to export as Markdown. Each item needs role and text. |
| filename | string | "conversation.md" | Download filename. |
| formatMessage | (message, index) => string | - | Optional formatter for each Markdown line. |
| children | React.ReactNode | - | Optional custom icon or label inside the download button. |