# 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.pdfPDF · 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: `