# Chat & Messaging Components for conversation and chat UI. Compose these instead of hand-rolling bubbles, scroll containers, dividers, or attachment cards. Install: `npx shadcn@latest add message-scroller message bubble attachment marker trace code-block` The same component names and props ship for both `base` and `radix`; only composition differs (`render` vs `asChild`). See [base-vs-radix.md](./base-vs-radix.md). ## Contents - Scrollable threads use MessageScroller - Message rows use Message - Message surfaces use Bubble - Attachments use Attachment - System notes and dividers use Marker - Assistant activity uses Trace - Code and tool output use CodeBlock - Streaming, anchoring, and jump-to-latest are built in - Escape hatch: the scroller hooks --- ## Scrollable threads use MessageScroller A conversation that scrolls, follows new messages, restores position, or jumps to a message uses `MessageScroller`. Don't build a raw overflow container with manual scroll wiring, and don't reach for `ScrollArea`. The parts nest in a fixed order. Every direct child of the content is wrapped in a `MessageScrollerItem` so the scroller can measure, anchor, preserve position, track visibility, and jump to it. `MessageScrollerButton` sits inside `MessageScroller`, after the viewport. **Incorrect:** ```tsx // Hand-rolled scroll container with manual stick-to-bottom logic.
{messages.map((m) => ( ))}
``` **Correct:** ```tsx {messages.map((message) => ( {/* ...message content... */} ))} ``` --- ## Message rows use Message `Message` lays out a single row: avatar, header, content, footer, with alignment. Group consecutive rows from one sender with `MessageGroup`. Don't rebuild the row from flex divs. `align="end"` is the current user's side; `align="start"` is everyone else. ```tsx {initials} {sender.name} {text} {time} ``` --- ## Message surfaces use Bubble The colored message surface is `Bubble` + `BubbleContent`, never a styled `div` with `bg-muted` / `bg-primary` and hand-managed corners. - `variant`: `default`, `secondary`, `muted`, `tinted`, `outline`, `ghost`, `destructive`. - `align`: `start` or `end` (matches the `Message` side). `BubbleReactions` renders the reaction cluster. `side` (`top` | `bottom`) and `align` (`start` | `end`) position it against the bubble. Don't lay reactions out with absolutely-positioned `Badge`s. **Incorrect:** ```tsx
{text}
``` **Correct:** ```tsx {text} 👍 2 ``` --- ## Attachments use Attachment File and image attachments use `Attachment`, not `Item` or a custom card. It carries upload state, so wire `state` to the real status rather than rendering a separate spinner. - `state`: `idle`, `uploading`, `processing`, `error`, `done`. `uploading` and `processing` apply the `shimmer` animation to the title automatically. - `size`: `default`, `sm`, `xs`. `orientation`: `horizontal`, `vertical`. - Use `AttachmentGroup` to lay out several attachments in a scrolling row. ```tsx homepage-feedback.pdf PDF · 2.4 MB ``` For an image, use `` with an `img` child. --- ## System notes and dividers use Marker Status lines ("Sarah joined the conversation"), date dividers ("Today"), and labeled separators are `Marker`, not a `Separator` plus a centered span. - `variant`: `default` (plain row), `separator` (centered label with rules on each side), `border` (bottom-bordered row). - `MarkerIcon` holds a leading icon; `MarkerContent` holds the label. **Incorrect:** ```tsx
Today
``` **Correct:** ```tsx Today ``` --- ## Assistant activity uses Trace What the assistant did or is doing (reasoning, tool calls, chain of thought, steps, sources, file reads) is a `TraceLine` in a `Trace`, not a hand-rolled `Collapsible` or a `Marker`. One line reports one thing; it may have detail. - `TraceLine` is always the line: a `TraceIcon` and a `TraceTitle`, then an optional `TraceDescription` for a count, a duration or a diff stat. `status` goes on the `TraceLine`. Never hand-roll a span for secondary text. - Behavior wraps the line. To make a line do something, wrap it in that thing's trigger: - nothing to open: the `TraceLine` alone; - expands: `TraceCollapsible` > `TraceCollapsibleTrigger` > `TraceLine`, then `TraceCollapsibleContent`. The trigger adds its own chevron; - link: `` > `TraceLine`; - overlay: `` > `TraceLine` (Dialog, Drawer and Popover the same). Aria: `