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. Each tail points toward its speaker, level with the avatar, and one drop shadow follows bubble and tail together, deepening under floating elevation.

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.

Kenji Sato
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
  • Only the last bubble of a run carries the tail, so a run reads as one connected shape
  • A grouped bubble hides its sender visually but still announces it to screen readers

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
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 UI 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 message renders on: "incoming" (left, neutral surface) or "outgoing" (right, the accent-filled surface). Default "incoming".

avatarNone
React.ReactNode

Avatar slot - typically an `<Avatar />`. Hidden (but its footprint reserved, so bubbles stay aligned) when `grouped`.

classNamesNone
Partial<Record<"meta" | "avatar" | "sender" | "bubble", string>>

Per-slot class overrides, for styling one part without wrapping the whole bubble.

groupedfalse
boolean

Marks a bubble inside a same-sender run: hides avatar/sender/timestamp/status and tightens the gap. Leave the run's last message ungrouped (the default); the consumer decides what groups.

senderNone
React.ReactNode

Sender name, shown above the bubble. Hidden when `grouped`.

statusNone
ChatBubbleStatus

Delivery/read status, shown next to the timestamp as an icon + text label. Hidden when `grouped`.

timestampNone
React.ReactNode

Timestamp string/node, shown below the bubble in a de-emphasized style so it never reads as the primary content. Hidden when `grouped`.

Also accepts everything from React.HTMLAttributes<HTMLDivElement>.

ChatBubble.Attachment props

name *None
React.ReactNode

File/attachment name.

classNamesNone
Partial<Record<"preview", string>>

Per-slot class overrides. `preview` is the artwork box.

iconPaperclip
IconComponent

Icon shown before the name - defaults to a generic paperclip. Ignored when `preview` is given.

metaNone
React.ReactNode

Secondary detail, e.g. a file size or an audio duration ("2.4 MB", "0:42").

onClickNone
React.MouseEventHandler<HTMLButtonElement>

Renders a keyboard-accessible `<button type="button">` (e.g. open/download). Without it the chip is a static `<div>`, so it can sit inside a consumer's own `<a>` without nesting.

previewNone
React.ReactNode

Artwork in place of the icon (thumbnail, poster), cropped to a 40px square (`classNames.preview` resizes it). Give it an empty `alt` when `name` already describes the file.

Also accepts everything from Omit<React.HTMLAttributes<HTMLDivElement>, "onClick">.

ChatBubble.Typing props

label"Typing"
string

Text announced in place of the hidden animated dots. Default "Typing". Pass a name for group threads ("Priya is typing") or a translated string.

Also accepts everything from React.HTMLAttributes<HTMLSpanElement>.

Coding agents read this reference, with its examples, from the version your project has installed, through the Fuji UI MCP server. Set up your agent