Message
Displays a message in a conversation, with optional avatar, header, footer, and alignment.
- Status
- Since
0.1.0- Accessibility pattern
- presentational layout
Last updated
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Message before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify messageInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/messageRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
Usage
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import {
Message,
MessageAvatar,
MessageContent,
} from "@/components/ui/message";
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage src="/avatars/01.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>How can I help you today?</BubbleContent>
</Bubble>
</MessageContent>
</Message>;Message owns the row layout — avatar, alignment, header and footer. Render the visible message
surface inside it with Bubble. For the scroll container around a whole
conversation, use MessageScroller.
Anatomy
Examples
Composition
MessageContent is the column beside the avatar: the header sits above the message surface and the
footer below it.
Message
├── MessageAvatar
└── MessageContent
├── MessageHeader
├── Bubble
└── MessageFooterMessageGroup stacks consecutive messages from the same sender.
MessageGroup
├── Message
└── MessageFeatures
- Start and end alignment for sender and receiver rows via the
alignprop - Avatar slot that anchors to the bottom of the message and stays clear of the footer
- Header and footer slots for sender names, status, and message actions
- Footer follows the message side; actions stay aligned on
align="end"rows - Group wrapper for stacking consecutive messages from the same sender
- Customizable styling through the
classNameprop on every part
Avatar
Use MessageAvatar to render an avatar next to the message. Set align="end" on the message to move
the avatar to the end of the row.
| align | Description |
|---|---|
start | Align the message to the start of the conversation. |
end | Align the message to the end of the conversation. |
Group
Use MessageGroup to stack consecutive messages from the same sender. Render an empty
MessageAvatar on the earlier rows to keep them aligned with the avatar on the last one.
Header and Footer
Use MessageHeader for a sender name and MessageFooter for metadata such as a delivery or read
status. The header does not re-justify its contents with align — its text reads from the start
either way; the footer follows the message side.
Actions
Place message-level actions in MessageFooter — copy, retry or feedback buttons. Icon-only actions
each carry an aria-label.
Attachment
An Attachment is a sibling of the bubble inside MessageContent, so
it inherits the row's alignment. A vertical image attachment sits above the bubble that talks about
it; a file attachment sits below.
API Reference
Message
The message row wrapper. A <div>; every other div prop passes through.
| Prop | Type | Default | Description |
|---|---|---|---|
align | "start" | "end" | "start" | The alignment of the message in the conversation. |
className | string | — | Additional classes to apply to the row. |
MessageGroup
Groups consecutive messages from the same sender. It adds no props of its own — a <div> with
data-slot="message-group" and className.
MessageAvatar
The avatar slot, aligned to the bottom of the message. When the row has a MessageFooter, the avatar
shifts up so it stays level with the message surface instead of the footer. It adds no props of its
own — a <div> with data-slot="message-avatar" and className.
MessageContent
Wraps the header, the message surface and the footer. It adds no props of its own — a <div> with
data-slot="message-content" and className.
MessageHeader
Displays content above the message, such as a sender name; its contents are not re-justified by
align. It adds no props of its own — a <div> with data-slot="message-header" and
className.
MessageFooter
Displays content below the message, such as status or actions; aligns to the message side. It adds no
props of its own — a <div> with data-slot="message-footer" and className.
Accessibility
Messageis a presentational layout wrapper — six plain<div>s. Every accessible semantic comes from what you put inside it.- Action buttons in
MessageFooterare usually icon-only, so give each one anaria-label. - For an in-progress message, use a
Markerwithrole="status"so assistive tech announces the update as it appears. - The component renders no control, so it contributes no focus affordance: whatever you render inside
it brings the global 2px
:focus-visibleoutline frombase.css. MessageContentismin-w-0and wraps on word boundaries, so a long unbroken string reflows instead of widening the row past the viewport.
| Contract | States tested |
|---|---|
| Behaviour | default |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test |
| Visual | default |
Do / Don't
Deviations
Upstream's file plus packages/ui/upstream/patches/message.patch. Every hunk:
- NO STYLING HUNK AT ALL —
Messageis six plain<div>s with a class each: no control, no focus affordance, no cursor, no disabled state, no live region and no portal, so not one row in the exception map reaches it. A11Y-2 is audited and not applicable — nothing here is a pointer target.message.test.tsxasserts the part list, thealignswitch and the avatar/footer offset, so a future upstream that adds a control to this file fails there. - DOC-2 —
import { cn } from "cn"becomes@vegastack/design; our npm layer ownscn. - DOC-1 — prettier reflow plus the
registry-stamp.mjsprovenance header the three-copy model needs; no decision of its own.