Hi! How can I help you today?
Chat Message
A single chat message: sender-aware wrapper providing alignment, avatar, name, and metadata around the message content.
Examples
Section titled “Examples”<ChatMessage {...args}> <ChatMessageBubble>Hi! How can I help you today?</ChatMessageBubble></ChatMessage>Senders
Section titled “Senders”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>Bubble Variants
Section titled “Bubble Variants”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>Full Width Content
Section titled “Full Width Content”| Model | Requests | Tokens |
|---|---|---|
| Atlas | 1,842 | 3.2M |
| Nova | 967 | 1.1M |
| Ember | 413 | 620K |
<div className={columnStyle}> <ChatMessage sender="assistant"> <ChatMessageBubble width="full"> <Table columns={usageColumns} data={usageData} density="compact" idKey="model" label="Model usage" /> </ChatMessageBubble> </ChatMessage></div>Grouped Bubbles
Section titled “Grouped Bubbles”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>With Avatar And Name
Section titled “With Avatar And Name”N
Navi
Hello! I looked into your question.
CP
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>Metadata Statuses
Section titled “Metadata Statuses”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>System Messages
Section titled “System Messages”Conversation started
Model upgraded
Today
<div className={columnStyle}> <ChatSystemMessage>Conversation started</ChatSystemMessage> <ChatSystemMessage icon={<Icon icon={Sparkles} size="sm" />}> Model upgraded </ChatSystemMessage> <ChatSystemMessage variant="divider">Today</ChatSystemMessage></div>ChatMessage
Section titled “ChatMessage”A single chat message: sender-aware wrapper providing alignment, avatar, name, and metadata around the message content.
| Prop | Type | Default | Description |
|---|---|---|---|
avatar | ReactNode | — | Avatar rendered beside the message. Ignored for system messages. |
children* | ReactNode | — | Message body — typically one or more ChatMessageBubble elements followed by a ChatMessageMetadata. |
className | string | — | Additional CSS class names applied to the root element. |
data-testid | string | — | Test ID applied to the root element. |
density | "compact" | "balanced" | "spacious" | 'balanced' | Density preset controlling gaps. Defaults to the surrounding ChatMessageList density. |
metadata | ReactNode | — | 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. |
name | ReactNode | — | 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. |
ref | Ref<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. |
style | CSSProperties | — | Inline styles applied to the root element. |
aria-describedby | AriaAttributes['aria-describedby'] | — | Identifies the element(s) that describe the region. |
aria-label | AriaAttributes['aria-label'] | — | Accessible label for the region. |
aria-labelledby | AriaAttributes['aria-labelledby'] | — | Identifies the element(s) that label the region. |
id | string | — | HTML id attribute applied to the root element. |
ChatMessageBubble
Section titled “ChatMessageBubble”The styled chat "bubble". Reads sender and density from the surrounding ChatMessage so it aligns and colors itself automatically.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Bubble content — text or any ReactNode. |
className | string | — | Additional CSS class names applied to the bubble element. |
data-testid | string | — | 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. |
metadata | ReactNode | — | Metadata rendered below the bubble, aligned with the bubble padding — typically a ChatMessageMetadata. Use on the last bubble in a message. |
name | ReactNode | — | Sender name rendered above the bubble, aligned with the bubble padding. Use on the first bubble in a message. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the bubble element. |
style | CSSProperties | — | 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. |
width | WidthValue | — | Bubble width. Numbers are pixels, strings are used as-is, 'full' fills the message column. When set, replaces the default maximum-width cap. |
aria-describedby | AriaAttributes['aria-describedby'] | — | Identifies the element(s) that describe the region. |
aria-label | AriaAttributes['aria-label'] | — | Accessible label for the region. |
aria-labelledby | AriaAttributes['aria-labelledby'] | — | Identifies the element(s) that label the region. |
id | string | — | HTML id attribute applied to the root element. |
ChatMessageMetadata
Section titled “ChatMessageMetadata”Metadata row for a chat message, rendered as `timestamp · footer · status` (reversed for user messages). Renders nothing when all parts are empty.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS class names applied to the root element. |
data-testid | string | — | Test ID applied to the root element. |
footer | ReactNode | — | Footer content — model info, ratings, reactions. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the root element. |
status | "error" | "delivered" | "read" | "sending" | "sent" | — | Message delivery status, shown as an icon with a label. |
style | CSSProperties | — | Inline styles applied to the root element. |
timestamp | ReactNode | — | Timestamp content — typically a <Timestamp format="time">. |
aria-describedby | AriaAttributes['aria-describedby'] | — | Identifies the element(s) that describe the region. |
aria-label | AriaAttributes['aria-label'] | — | Accessible label for the region. |
aria-labelledby | AriaAttributes['aria-labelledby'] | — | Identifies the element(s) that label the region. |
id | string | — | HTML id attribute applied to the root element. |
ChatSystemMessage
Section titled “ChatSystemMessage”Centered system notice for chat threads: date separators, "conversation started", membership changes, and similar non-sender content.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | System message content — text or any ReactNode. |
className | string | — | Additional CSS class names applied to the root element. |
data-testid | string | — | Test ID applied to the root element. |
icon | ReactNode | — | Icon rendered before the text. Ignored by the divider variant. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the root element. |
style | CSSProperties | — | 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-describedby | AriaAttributes['aria-describedby'] | — | Identifies the element(s) that describe the region. |
aria-label | AriaAttributes['aria-label'] | — | Accessible label for the region. |
aria-labelledby | AriaAttributes['aria-labelledby'] | — | Identifies the element(s) that label the region. |
id | string | — | HTML id attribute applied to the root element. |