Message
The layout shell of a chat message.
Overview
The structural half of a chat message: avatar + content column with optional
header, footer and action rows, flipped with align="end" for the outgoing
side. Pair it with Bubble for the speech surface and MessageScroller for
the conversation viewport.
Typography follows the kit scale — the message body rides type-body (the same
voice as Bubble), the header is a type-label-sm sender name and the footer a
type-caption meta line. Both meta lines read in on-surface-variant so they
recede behind the message itself.
Building an AI chat with useChat/streaming? The kit also ships Vercel AI
Elements — see the AI section of these docs. Use these primitives when you
want hand-rolled chat UI directly on the kit's tokens.
$ npx morpha-ui add messageExamples
Avatar
The avatar is pinned to the bottom of the column, so it always hugs the last
bubble of the turn. align="end" reverses the row for the outgoing side.
Group
Consecutive turns from the same sender: one Message shell wrapping a
BubbleGroup, with a single avatar and timestamp for the whole run.
Header and footer
MessageHeader names the sender; MessageFooter carries the time and delivery
state.
Actions
MessageActions holds message-level controls — copy, retry, feedback. The row is
visible by default, since a generated reply always carries its controls. Pass
reveal="hover" for the quieter treatment, where it fades in lifting a soft blur
once the message is hovered or focused (and stays permanently visible on devices
that can't hover).
Each control is a MessageAction: a containerless icon button named by a plain
tooltip on hover. MessageCopyAction is the ready-made copy control — it writes
text to the clipboard and swaps its glyph to a check for two seconds to
confirm.
Attachment
Images and files sit inside MessageContent as siblings of the bubble: media in
a bare ghost bubble, files in the kit's Attachment chip.
Branching
MessageBranch navigates alternative versions of one turn (regenerated
replies): MessageBranchContent shows only the active child, and the selector
row — previous, "1 of 3", next — rides the same type-caption meta voice as
the header/footer lines, wrapping around at the ends. MessageToolbar lays the
selector and MessageActions out on one row.
Installation
Morpha UI components are distributed via the Morpha CLI: npx morpha-ui add message. In the meantime, since this is the base shadcn component, you can
also add it directly:
npx shadcn@latest add messageAPI Reference
Prop
Type
MessageActions
Prop
Type
MessageAction
Prop
Type
MessageCopyAction
Prop
Type
MessageBranch
Prop
Type
Anatomy
<MessageGroup>
<Message align="start">
<MessageAvatar />
<MessageContent>
<MessageHeader />
<MessageBranch>
<MessageBranchContent>
<Bubble>
<BubbleContent />
</Bubble>
</MessageBranchContent>
<MessageToolbar>
<MessageBranchSelector>
<MessageBranchPrevious />
<MessageBranchPage />
<MessageBranchNext />
</MessageBranchSelector>
<MessageActions />
</MessageToolbar>
</MessageBranch>
<MessageFooter />
</MessageContent>
</Message>
</MessageGroup>MessageGroup, MessageAvatar, MessageContent, MessageHeader,
MessageFooter, MessageActions and MessageToolbar take no props of their
own — they are plain divs and accept className plus any native attribute.
Branching is optional: without alternatives, put the Bubble directly in
MessageContent.
Accessibility
- Keep sender and time visible (header/footer) — alignment and color alone don't convey who is speaking.
- Icon-only controls in
MessageActionsneed anaria-label; the row is keyboard reachable and reveals itself on focus. - The shell is plain content; interactive parts inside (links, reactions, attachments) carry their own semantics.