Chat Thread
The whole conversation around the composer. Your question pins to the top while the answer streams, checkpoints on the side jump between messages, and every reply can be copied, edited, retried, rated and switched between versions. Replies render Markdown with code blocks, tables and citations, and thinking, tool calls and Prompt Input slot straight in.
Chat Thread is the conversation around the composer: your messages, the model’s replies, and everything you do with them. Each reply can hold thinking, tool calls and formatted Markdown with code and citations, while the thread takes care of scrolling, editing, versions and errors.
It slots in with the other AI blocks instead of replacing them. Pass Prompt Input as the composer, put Reasoning, ToolCalls and Markdown inside each reply, and the thread handles the rest.
- Starts centered. An empty chat shows your empty state with the composer in the middle of the screen. Once there are messages, the composer docks at the bottom without remounting, so focus and draft text stay put.
- Pins your question. The message you just sent moves to the top while its answer streams below it, so you read from the start instead of chasing the bottom.
- Follows without fighting. New text keeps the view at the bottom until you scroll up. A button appears to jump back to the latest message.
- Checkpoints. A rail of short bars on the right, one per message you sent. Hover one to preview the message, click to jump to it. The bar for where you are is longer. Hidden on phones.
- Copy, edit, try again. Hover a message for its actions. Edit opens the message in place: Enter sends, Escape cancels, and unchanged edits are ignored. Try again keeps the old reply as a version.
- Versions. Edits and retries become versions with ‹ 1/2 › arrows on both the message and the reply, so nothing is lost.
- Feedback. Thumbs up and down toggle, fill in when chosen and thank the person quietly.
- Errors and stops. A failed reply shows what went wrong with Try again and its versions. A stopped reply says Stopped instead of looking finished.
- Formatted replies. Put the Markdown block inside a reply for headings, lists, tables, callouts, task lists and code blocks, with [1] marks as citation chips, all while streaming.
- Attachments. Images you sent show as thumbnails above your message, and other files as chips with their type and size.
- Dividers and time. Separate days or model switches with ChatDivider. Each message shows its time on hover.
- Earlier messages. Load older history from the top without the view moving.
Add the Pro registry to components.json
components.json Add your token
Create a token on your account page and put it in
.env.localasHEXTAUI_PRO_TOKEN.Add the block
pnpm dlx shadcn@latest add @hextaui-pro/chat-thread
With the AI SDK
Map useChat messages to the thread. Reasoning parts go to Reasoning, tool parts to ToolCalls and text to Markdown. Pin the latest user message, use regenerate for Try again, and send an edit again from that point.
Anatomy
The parts you compose, from the outside in.
| Part | Description |
|---|---|
ChatThread | The frame: scroller, checkpoints, empty state and composer slot. |
ChatUserMessage | Your message: attachments, bubble, time, versions, copy and edit. |
ChatAssistantMessage | A reply. Put Reasoning, ToolCalls and Markdown inside it; it adds the actions, error and stopped states. |
ChatDivider | A labelled line between groups of messages. |
ChatAttachments, ChatAction, ChatCopy, ChatBranchSwitch, ChatEditor | The pieces the messages use, exported for custom layouts. |
| Prop | Type | Default |
|---|---|---|
childrenMessages and dividers, in order. | ReactNode | – |
composerUsually Prompt Input. Centered when empty, docked at the bottom otherwise. | ReactNode | – |
emptyShown above the composer when there are no messages. | ReactNode | – |
busyMarks the conversation busy for assistive technology while a reply streams. | boolean | false |
hasOlderShows “Load earlier messages” at the top. | boolean | false |
loadingOlderShows a spinner on that button. The scroll position is restored once it turns false. | boolean | false |
onLoadOlderPrepend older messages here. | () => void | – |
| Prop | Type | Default |
|---|---|---|
idStable id. Keep it the same across versions so the view doesn’t jump. | string | – |
textThe message. Also used for the checkpoint preview. | string | – |
pinScroll this message to the top when it appears. Set it on the message just sent. | boolean | false |
files{ id, name, size?, type?, url? }. Images with a url show as thumbnails. | ChatFile[] | – |
timeShown on hover, in the reader’s locale. | Date | – |
branch{ index, count, onChange } for the version arrows. | ChatBranch | – |
onEditShows Edit. Called with the new text when it changed. | (text: string) => void | – |
attachmentsCustom content above the bubble. | ReactNode | – |
| Prop | Type | Default |
|---|---|---|
idStable id. | string | – |
childrenReasoning, ToolCalls, Markdown or anything else. | ReactNode | – |
textPlain text for Copy. | string | – |
streamingHides the actions until the reply finishes. | boolean | false |
lastKeeps the actions visible instead of showing them on hover. | boolean | false |
metaRight side of the action row, such as the model and effort. | ReactNode | – |
branchVersion arrows for retries. | ChatBranch | – |
feedbackThe current rating. | "up" | "down" | null | null |
onFeedbackShows the thumbs. Called with null when a rating is undone. | (feedback) => void | – |
onRetryShows Try again. | () => void | – |
errorShows the message with Try again instead of the actions. | string | null | – |
stoppedMarks a reply that was stopped early. | boolean | false |
| Prop | Type | Default |
|---|---|---|
childrenThe label, such as Today or “Switched to Nova 3 Max”. | ReactNode | – |
| Key | Action |
|---|---|
| Tab | Moves through the messages’ actions. They appear on focus, not only on hover. |
| Enter | Sends an edited message. |
| ShiftEnter | Adds a line while editing. |
| Esc | Cancels an edit. |
| ↑↓PgUpPgDn | Scroll the conversation when it has focus. |
- The conversation is a labelled region holding a log, so new messages are announced as they arrive and the region is marked busy while a reply streams.
- Every icon action has a label and tooltip. Thumbs use aria-pressed, Copy and feedback confirm through a polite live region, and errors use role=alert.
- Checkpoints are a navigation landmark of buttons named “Message 2: …”, and the current one has aria-current.
- Version arrows are a group named “Version 1 of 2”.
- The editor focuses itself with the caret at the end and returns to the message on Cancel. Enter waits while an input method is composing.
- Focus rings are never clipped by the scroller, and actions stay visible on touch screens.
Code
2 files, added to components/blocks/chat-thread.