Skip to content
Component

Chat Bubble

Incoming/outgoing message bubbles with avatar, sender, timestamp, and delivery status. Group consecutive messages from the same sender to suppress repeated metadata, Messages/Slack-style.

Conversation

align='incoming' (default) renders on the left with a neutral surface; align='outgoing' renders on the right with the accent-filled surface.

PN
Priya Nair
Can you review the PR before standup?
9:41 AM
On it now, give me ten minutes.
9:42 AMDelivered

Delivery status

status renders as an icon plus a text label next to the timestamp - never color alone.

Deploying now
10:02 AMSent
Build passed
10:03 AMDelivered
Live on production
10:05 AMRead

Grouped runs

grouped suppresses the avatar/sender/timestamp/status and tightens spacing. Render the last bubble in a run with grouped={false} (the default) so metadata surfaces once per run.

Pushed the fix to main
KS
Kenji Sato
CI is green, ready to deploy
2:14 PMDelivered
  • ChatBubble doesn't know about a list of messages - the consumer decides which consecutive bubbles to group

With an attachment

ChatBubble.Attachment is a small file/media chip for use inside children - pass onClick to make it a real, keyboard-accessible button.

Here's the signed contract.
4:20 PMRead

ChatBubble props

align"incoming"
"incoming" | "outgoing"

Which side the bubble renders on.

avatarNone
ReactNode

Avatar slot, hidden (footprint reserved) when grouped.

senderNone
ReactNode

Sender name above the bubble, hidden when grouped.

timestampNone
ReactNode

De-emphasized timestamp below the bubble, hidden when grouped.

statusNone
"sent" | "delivered" | "read"

Delivery/read state shown next to the timestamp, hidden when grouped.

groupedfalse
boolean

Marks this bubble as part of a consecutive run from the same sender.

ChatBubble.AttachmentNone
compound part

icon / name / meta / onClick - a file or media chip inside the bubble.

classNamesNone
{ avatar, sender, bubble, meta }

Per-slot class overrides.

CriterionStatusNote
Keyboard supportSupportedNot an interactive widget by default; Attachment renders a real, focusable <button type="button"> only when onClick is passed.
Focus managementNot applicableNot an overlay - no focus trap or portal involved.
Screen reader labelsSupportedStatus renders as a visible icon plus text label, never color alone.
Reduced motionSupportedNo motion beyond the shared Fuji transition tokens, which zero under prefers-reduced-motion.
Reduced transparencyNot applicableUses opaque surfaces in every theme.
Mobile touch behaviorSupportedBubbles reflow within their max-width container; verified down to 320px.

API reference

align"incoming"
"incoming" | "outgoing"

Which side the bubble renders on.

avatarNone
ReactNode

Avatar slot, typically an <Avatar />.

senderNone
ReactNode

Sender name shown above the bubble.

timestampNone
ReactNode

De-emphasized timestamp below the bubble.

statusNone
"sent" | "delivered" | "read"

Delivery/read state, shown as an icon plus text label next to the timestamp.

groupedfalse
boolean

Suppresses avatar/sender/timestamp/status and tightens spacing for a consecutive run.

ChatBubble.AttachmentNone
compound part

File/media chip: icon, name, meta, and an optional onClick to make it a real button.

classNameNone
string

Additional classes applied to the component root.