Message
Layout primitives for a conversation row — avatar anchoring, a content column, header/footer slots, and start/end alignment. Server-safe.
- Status
- Since
0.1.0- Accessibility pattern
- presentational layout
Last updated
Install
Add Message from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/messageUsage
import { Avatar } from "@/components/ui/avatar";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import {
Message,
MessageAvatar,
MessageContent,
} from "@/components/ui/message";
<Message>
<MessageAvatar>
<Avatar fallback="AL" />
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>Hello there!</BubbleContent>
</Bubble>
</MessageContent>
</Message>;Anatomy
Message is pure layout — it owns no colours and is server-safe. Compose
Avatar, Bubble, and
Marker as children.
Message— one row (data-slot="message",data-align).align="end"reverses the row for the current user's own messages.MessageGroup— stacks consecutive messages from one sender.MessageAvatar— anchors anAvatarto the bottom of the row.MessageContent— the vertical column (bubbles, header, footer).MessageHeader/MessageFooter— small muted lines above / below the bubble.
Examples
A conversation
Received (align="start") and sent (align="end") rows, with an avatar, a
header, and a footer.
Message group
MessageGroup stacks consecutive messages from the same sender, with the avatar
anchored once to the group.
Header and footer
MessageHeader sits above the bubble (sender name) and MessageFooter below
(status / timestamp). With a footer, the avatar lifts to stay aligned.
Actions
Put a row of Buttons in MessageFooter for per-message actions. Pair a
destructive bubble with a retry affordance for a failed message.
Attachments
Compose rich content inside a bubble — a ghost bubble for flush media, or an
outline bubble framing a file chip.
Motion
Pass animateIn on a message you append after mount — a streamed reply, or the message the
user just sent — to fade + rise it in (motion-enter-up). It's off by default: an existing
transcript rendered on page load must not animate every row. Bubble takes the same prop, so set
either or both; a MessageScroller composes fine with it.
Ghost bubble
MessageHeader and MessageFooter drop their inline padding when the bubble
uses the ghost variant, so the muted lines align flush with edge-to-edge media.
Agent transcripts
The four chat-family pieces compose a full agent transcript:
- Thinking marker —
Marker+ theshimmerutility:<Marker><MarkerContent className="shimmer">Thinking</MarkerContent></Marker> - Tool calls —
ToolCallChiprows between messages; a spinner leading slot while running, then an icon +metaonce resolved. - Artifacts — an
Attachmentwith the produced thing's icon inAttachmentMedia, its name inAttachmentTitle, and a statusBadgecomposed inAttachmentActions. - Code + results —
CodeBlockfor the query and a compactTablewithclassName="font-mono text-code-sm"cells for inline results. - Compose states — keep the submit or stop control's accessible name synchronized with its action.
API Reference
Message is the only part with its own prop (align). MessageGroup,
MessageAvatar, MessageContent, MessageHeader, and MessageFooter are plain
layout wrappers — they accept the standard div props plus className.
| Prop | Type | Default | Description |
|---|---|---|---|
align | "end" | "start" | 'start' | Which side the message sits on.
- start: received message — avatar/content read left-to-right (default).
- end: sent message — the row reverses so content hugs the end edge. |
animateIn | boolean | false | Opt-in entry animation (motion-enter-up, a fade + slight rise) for a
message row that is newly appended to a live thread — e.g. a message that
just streamed in, or one the user just sent. **Default off**: an existing
transcript rendered on page load must not animate every row. Enable it only
on the message(s) you append after mount (mirrors Bubble's animateIn;
set either or both — a MessageScroller composes fine with it). |
Data attributes and CSS variables on Message
| Attribute | Values |
|---|---|
data-align | mirrors a prop or state value |
data-slot | "message" |
Accessibility
Messageis presentational layout — it adds no roles. Convey conversation semantics at the container level (e.g. alog/feedregion) as your app requires.alignonly changes visual order; DOM order stays logical for screen readers and keyboard users.- Pair with
Avatar(which carries the accessible name) rather than relying on the avatar image alone.
| Contract | States tested |
|---|---|
| Behaviour | default |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test |
| Visual | default |
Do / Don't
Marker
An inline conversation marker — status lines, system notes, and labelled dividers — built on Base UI render, polymorphic to a link or button.
Bubble
A chat speech bubble — seven token-driven variants (incl. a brand-tinted surface), start/end alignment, interactive content, and a floating reactions chip.