ChatMessage

ChatMessage is a multi-part component for displaying chat messages — assistant replies on the left, user messages on the right. Built-in typing animation, delivery status, and hover actions.

2
Variants
3
Sizes
Compound
4 Parts
Pure
React

Playground

Preview
messengerbubbledefault
Sure! Let me help you with that.
12:33
That makes sense!
12:34
Message
Type
AI Color
User Color
Size
Radius
Tail
Status
Avatar
Size
Options
Options
Options
<div className="flex flex-col gap-4">
  <ChatMessage avatarSize="md">
    <ChatMessageAvatar />
    <div className="flex flex-col gap-1">
      <ChatMessageContent>Sure! Let me help you with that.</ChatMessageContent>
      <ChatMessageFooter timestamp="12:33" />
    </div>
  </ChatMessage>

  <ChatMessage role="user" color="muted">
    <div className="flex flex-col gap-1 items-end">
      <ChatMessageContent>That makes sense!</ChatMessageContent>
      <ChatMessageFooter timestamp="12:34" />
    </div>
  </ChatMessage>
</div>

Variants

How do design tokens work?
12:34
Bubble
Bordered bubble with background — the standard chat message look.
Default
How do design tokens work?
They map values to semantic names.
Flat
No background or border — minimal style for content-forward layouts.
Minimal

Sizes

sm
Padding12 × 6px
Font13px
Avatar24px
default
Padding14 × 8px
Font14px
Avatar28px
lg
Padding16 × 10px
Font16px
Avatar32px

Features

Role

role="assistant" aligns left; role="user" aligns right. Layout and alignment switch automatically based on role.

How can I help you?
12:34
That makes sense!
Read12:35
<ChatMessage role="assistant">
  <ChatMessageAvatar />
  <div className="flex flex-col gap-1">
    <ChatMessageContent>How can I help you?</ChatMessageContent>
    <ChatMessageFooter timestamp="12:34" />
  </div>
</ChatMessage>

<ChatMessage role="user" color="muted">
  <div className="flex flex-col gap-1 items-end">
    <ChatMessageContent>That makes sense!</ChatMessageContent>
    <ChatMessageFooter timestamp="12:35" status="read" />
  </div>
</ChatMessage>

UI Type

Messenger uses bubble-style chat UI — History uses flat minimal layout for log-style views. Pick the type that fits your use case.

Messenger
Sure! Let me help.
12:33
That makes sense!
Read12:34
History
Sure! Let me help.
That makes sense!

Typing

Set typing=true to show animated typing dots inside the Content area — use while the AI response streams in.

Here is the previous message.
12:34
<ChatMessage role="assistant" typing>
  <ChatMessageAvatar />
  <ChatMessageContent />
</ChatMessage>

Actions

Pass a ReactNode to actions to reveal action buttons on hover — copy, react, or any custom action.

Hover over the bubble to reveal actions.
12:34
<ChatMessage
  role="assistant"
  actions={
    <button className="p-1 rounded hover:bg-background-muted">
      <svg>...</svg>
    </button>
  }
>
  <ChatMessageAvatar />
  <div className="flex flex-col gap-1">
    <ChatMessageContent>How can I help?</ChatMessageContent>
    <ChatMessageFooter timestamp="12:34" />
  </div>
</ChatMessage>

API

Component Structure

ChatMessage— Compound · Pure React
ChatMessageContext provider + flex container
ChatMessageAvatarAvatar — image, initials, or icon
ChatMessageContentBubble or flat message content
ChatMessageFooterTimestamp and delivery status

Multi-part component — ChatMessage (root), ChatMessageAvatar, ChatMessageContent, ChatMessageFooter.

Props

ChatMessage

role"assistant"
"assistant" | "user"

Sender role — assistant aligns left, user aligns right with matching bubble colors

variant"bubble"
"bubble" | "flat"

Bubble style — bubble (bordered) or flat (no background)

color"default"
"default" | "muted" | "primary" | "dark"

Bubble background — default (bordered), muted (subtle bg), primary (brand), dark

size"default"
"sm" | "default" | "lg"

Size scale — sm, default, or lg

radius"2xl"
"md" | "lg" | "xl" | "2xl"

Bubble corner radius

tailtrue
boolean

Asymmetric tail — zeroes the corner radius on the avatar side of the bubble

avatarSizeundefined
"sm" | "md" | "lg"

Avatar size — also adjusts the gap between the avatar and bubble

typingfalse
boolean | { variant?: "dots" | "cursor", color?: "default" | "primary" | "muted", speed?: "slow" | "default" | "fast", label?: string, showLabel?: boolean }

Show animated typing dots inside the Content area

actionsundefined
ReactNode

Action buttons revealed on hover — copy, react, etc.

classNameundefined
string

Additional CSS classes

ChatMessageAvatar

size"md"
"sm" | "md" | "lg"

Avatar display size

srcundefined
string

Avatar image URL

alt"Avatar"
string

Alt text for the avatar image

initialsundefined
string

Initials shown when no image (1–2 characters)

iconundefined
ReactNode

Custom icon rendered inside the avatar

classNameundefined
string

Additional CSS classes

ChatMessageContent

classNameundefined
string

Additional CSS classes

ChatMessageFooter

timestampundefined
string

Pre-formatted timestamp string (e.g. "12:34 PM")

statusundefined
ReactNode | "sending" | "sent" | "read" | "error"

Delivery status — sending, sent, read, or error

sizeundefined
"sm" | "default" | "lg"

Size override for the footer — defaults to context value from ChatMessage root

classNameundefined
string

Additional CSS classes

Anatomy

1
2
AI
3
Message text
4Read12:34
1
ChatMessage
Role-aware flex layout container
2
ChatMessageAvatar
Sender avatar
3
ChatMessageContent
Styled message bubble
4
ChatMessageFooter
Timestamp and delivery state

Best Practices

Recommended

  • Include ChatMessageAvatar for role="assistant"
  • Set status on Footer for user messages to show delivery state
  • Leave ChatMessageContent empty when typing=true

Don't

  • Don't place ChatMessageAvatar inside role="user"
  • Don't use typing and children at the same time
  • Don't use for general content — use Card instead

Accessibility

Keyboard

TabMove focus to action buttons
Enter / SpaceActivate the focused action

ARIA / WCAG

  • Avatar has aria-hidden="true" (decorative element)
  • Delivery status uses visible text accessible to screen readers
  • Typing dots have aria-hidden="true"