Skip to content

Chat Message

A single chat message: sender-aware wrapper providing alignment, avatar, name, and metadata around the message content.

Hi! How can I help you today?
<ChatMessage {...args}>
<ChatMessageBubble>Hi! How can I help you today?</ChatMessageBubble>
</ChatMessage>
I'm an assistant message.
I'm a user message.
Conversation started
<div className={columnStyle}>
<ChatMessage sender="assistant">
<ChatMessageBubble>I'm an assistant message.</ChatMessageBubble>
</ChatMessage>
<ChatMessage sender="user">
<ChatMessageBubble>I'm a user message.</ChatMessageBubble>
</ChatMessage>
<ChatMessage sender="system">
<ChatSystemMessage>Conversation started</ChatSystemMessage>
</ChatMessage>
</div>
A filled bubble (default).
A ghost bubble: no background, but the same alignment.
<div className={columnStyle}>
<ChatMessage sender="assistant">
<ChatMessageBubble>A filled bubble (default).</ChatMessageBubble>
</ChatMessage>
<ChatMessage sender="assistant">
<ChatMessageBubble variant="ghost">
A ghost bubble: no background, but the same alignment.
</ChatMessageBubble>
</ChatMessage>
</div>
ModelRequestsTokens
Atlas1,8423.2M
Nova9671.1M
Ember413620K
<div className={columnStyle}>
<ChatMessage sender="assistant">
<ChatMessageBubble width="full">
<Table
columns={usageColumns}
data={usageData}
density="compact"
idKey="model"
label="Model usage"
/>
</ChatMessageBubble>
</ChatMessage>
</div>
Consecutive bubbles from one sender
tighten their corners on the sender side
so they read as one run.
<div className={columnStyle}>
<ChatMessage sender="user">
<ChatMessageBubble group="first">
Consecutive bubbles from one sender
</ChatMessageBubble>
<ChatMessageBubble group="middle">
tighten their corners on the sender side
</ChatMessageBubble>
<ChatMessageBubble group="last">
so they read as one run.
</ChatMessageBubble>
</ChatMessage>
</div>
Navi
Hello! I looked into your question.
Cindy
Thanks, that was fast!
2:31 PMRead
<div className={columnStyle}>
<ChatMessage
avatar={<Avatar name="Navi" size="small" />}
sender="assistant">
<ChatMessageBubble
metadata={
<ChatMessageMetadata
timestamp={
<Timestamp format="time" value="2026-07-14T14:30:00Z" />
}
/>
}
name="Navi">
Hello! I looked into your question.
</ChatMessageBubble>
</ChatMessage>
<ChatMessage avatar={<Avatar name="Cindy Park" />} sender="user">
<ChatMessageBubble
metadata={<ChatMessageMetadata status="read" timestamp="2:31 PM" />}
name="Cindy">
Thanks, that was fast!
</ChatMessageBubble>
</ChatMessage>
</div>
Message with sending status
2:30 PMSending
Message with sent status
2:30 PMSent
Message with delivered status
2:30 PMDelivered
Message with read status
2:30 PMRead
Message with error status
2:30 PMFailed
<div className={columnStyle}>
{(['sending', 'sent', 'delivered', 'read', 'error'] as const).map(
status => (
<ChatMessage key={status} sender="user">
<ChatMessageBubble
metadata={
<ChatMessageMetadata status={status} timestamp="2:30 PM" />
}>
Message with {status} status
</ChatMessageBubble>
</ChatMessage>
),
)}
</div>
Conversation started
Model upgraded
<div className={columnStyle}>
<ChatSystemMessage>Conversation started</ChatSystemMessage>
<ChatSystemMessage icon={<Icon icon={Sparkles} size="sm" />}>
Model upgraded
</ChatSystemMessage>
<ChatSystemMessage variant="divider">Today</ChatSystemMessage>
</div>

A single chat message: sender-aware wrapper providing alignment, avatar, name, and metadata around the message content.

PropTypeDefaultDescription
avatarReactNode—Avatar rendered beside the message. Ignored for system messages.
children*ReactNode—Message body — typically one or more ChatMessageBubble elements followed by a ChatMessageMetadata.
classNamestring—Additional CSS class names applied to the root element.
data-testidstring—Test ID applied to the root element.
density"compact" | "balanced" | "spacious"'balanced'Density preset controlling gaps. Defaults to the surrounding ChatMessageList density.
metadataReactNode—Metadata rendered below the message body. Use when the last child is raw content; if the last child is a ChatMessageBubble, prefer the bubble's metadata prop so it aligns with the bubble padding. Ignored for system messages.
nameReactNode—Sender name rendered above the message body. Use when the first child is raw content; if the first child is a ChatMessageBubble, prefer the bubble's name prop so it aligns with the bubble padding. Ignored for system messages.
refRef<HTMLElement>—Ref forwarded to the root element.
sender*"assistant" | "system" | "user"—Who authored the message. Controls alignment, avatar placement, and how child bubbles style themselves.
styleCSSProperties—Inline styles applied to the root element.
aria-describedbyAriaAttributes['aria-describedby']—Identifies the element(s) that describe the region.
aria-labelAriaAttributes['aria-label']—Accessible label for the region.
aria-labelledbyAriaAttributes['aria-labelledby']—Identifies the element(s) that label the region.
idstring—HTML id attribute applied to the root element.

The styled chat "bubble". Reads sender and density from the surrounding ChatMessage so it aligns and colors itself automatically.

PropTypeDefaultDescription
children*ReactNode—Bubble content — text or any ReactNode.
classNamestring—Additional CSS class names applied to the bubble element.
data-testidstring—Test ID applied to the bubble element.
group"first" | "last" | "middle"—Position within a multi-bubble group. Tightens the sender-side corners so consecutive bubbles read as one run: first tightens the bottom corner, middle both, last the top. Leave unset for standalone bubbles.
metadataReactNode—Metadata rendered below the bubble, aligned with the bubble padding — typically a ChatMessageMetadata. Use on the last bubble in a message.
nameReactNode—Sender name rendered above the bubble, aligned with the bubble padding. Use on the first bubble in a message.
refRef<HTMLDivElement>—Ref forwarded to the bubble element.
styleCSSProperties—Inline styles applied to the bubble element.
variant"ghost" | "filled"'filled'Visual variant: filled draws a background, ghost keeps only the inline padding so content aligns with sibling bubbles.
widthWidthValue—Bubble width. Numbers are pixels, strings are used as-is, 'full' fills the message column. When set, replaces the default maximum-width cap.
aria-describedbyAriaAttributes['aria-describedby']—Identifies the element(s) that describe the region.
aria-labelAriaAttributes['aria-label']—Accessible label for the region.
aria-labelledbyAriaAttributes['aria-labelledby']—Identifies the element(s) that label the region.
idstring—HTML id attribute applied to the root element.

Metadata row for a chat message, rendered as `timestamp · footer · status` (reversed for user messages). Renders nothing when all parts are empty.

PropTypeDefaultDescription
classNamestring—Additional CSS class names applied to the root element.
data-testidstring—Test ID applied to the root element.
footerReactNode—Footer content — model info, ratings, reactions.
refRef<HTMLDivElement>—Ref forwarded to the root element.
status"error" | "delivered" | "read" | "sending" | "sent"—Message delivery status, shown as an icon with a label.
styleCSSProperties—Inline styles applied to the root element.
timestampReactNode—Timestamp content — typically a <Timestamp format="time">.
aria-describedbyAriaAttributes['aria-describedby']—Identifies the element(s) that describe the region.
aria-labelAriaAttributes['aria-label']—Accessible label for the region.
aria-labelledbyAriaAttributes['aria-labelledby']—Identifies the element(s) that label the region.
idstring—HTML id attribute applied to the root element.

Centered system notice for chat threads: date separators, "conversation started", membership changes, and similar non-sender content.

PropTypeDefaultDescription
children*ReactNode—System message content — text or any ReactNode.
classNamestring—Additional CSS class names applied to the root element.
data-testidstring—Test ID applied to the root element.
iconReactNode—Icon rendered before the text. Ignored by the divider variant.
refRef<HTMLDivElement>—Ref forwarded to the root element.
styleCSSProperties—Inline styles applied to the root element.
variant"default" | "divider"'default'Visual variant: default is plain centered text, divider renders the content as a labeled horizontal divider (date-separator style).
aria-describedbyAriaAttributes['aria-describedby']—Identifies the element(s) that describe the region.
aria-labelAriaAttributes['aria-label']—Accessible label for the region.
aria-labelledbyAriaAttributes['aria-labelledby']—Identifies the element(s) that label the region.
idstring—HTML id attribute applied to the root element.