Message
Shows one turn of a conversation.
From
userdefault
agent
Bubble
defaultdefault
outline
Divider
- Context compacted
compaction
- Interrupted
interrupted
- Yesterday
day
- Waiting on you
handoff
States
sent
sending
not sent
agent done
footer in focus
agent failed
agent stopped
Usage
Rules
6 rules
- Must
- Build every agent turn with AgentTurn, its sections in order: reasoning, tool calls, the answer, the footer. Because every turn in a thread then shares one column and one header, read aloud, and a turn that failed or stopped shows its word in the same place.
- Never
- Put an agent turn in a card or a bubble; it is plain flow at the full width. Because the person's bubble is the only box in a thread, so a boxed answer reads as a second speaker and doubles every edge.
- Must
- Keep a message that did not send in the thread with MessageBubble status="fail" and MessageSendState state="failed" with onRetry. Because dropping it loses what the person wrote; the coral edge and "Not sent" say what happened and Retry sends the same text.
- Must
- Make the footer's actions ghost icon-sm Buttons or CopyButton, each with an aria-label. Because they show on hover and focus over a quiet line, and a glass key there would claim to be the turn's next step.
- Should
- Name the model that answered with MessageModel, and pass requested when a fallback answered. Because a turn answered by another model than the one picked should say so, and the footer is where a person looks.
- Should
- Mark compaction, interruption, a new day and a handoff with MessageDivider reason, not a rule of your own. Because reason sets the words, the glyph and the form, and a handoff to a person is the one centred line a thread has.
Accessibility
4 checks
- Each turn has a header with the speaker and time, read aloud even where it is not drawn.
- A failed or stopped agent turn says so in a word; the footer hides while the turn is live.
- Footer buttons show on hover where there is a pointer, always on touch, and on keyboard focus.
- A divider is role="separator" named by its words.
Edge cases
5 edge cases
- Long word or URL in a bubble
- Breaks anywhere; the bubble never passes 85% of the row.
- A message that did not send
- Keeps its text, the edge turns coral, "Not sent" and Retry sit under it.
- Fallback model
- MessageModel reads "glaze-small for glaze-large".
- Right to left
- The person's bubble sits at the start of the row instead of the end.
- Dark theme
- The bubble takes the dark shell, a step under the panel.
API
8 props
Message from'agent' | 'user'default'agent'Message size'default' | 'sm'default'default'AgentTurn name, time, statestring, ReactNode, 'live' | 'waiting' | 'fail' | 'stopped' | 'done'defaultstate 'done'MessageBubble variant, status'default' | 'outline', 'fail'default'default'MessageBubbleContent renderReactElementMessageSendState state, onRetry'sending' | 'sent' | 'failed', () => voidMessageFooter, MessageWorked, MessageModel, MessageMetapartsMessageDivider reason, to'compaction' | 'interrupted' | 'handoff' | 'day', 'person' | 'agent'defaultto 'person'
Tokens
12 tokens
--shell- #f1f1f0
--paper- #ffffff
--line-faint- rgb(5 5 5 / 0.06)
--line-control- rgb(5 5 5 / 0.15)
--line- rgb(5 5 5 / 0.10)
--fail- #e35e49
--radius-overlay- 10px
--type-body- 400 14px/1.5 var(--font-sans)
--type-caption- 400 12px/1.35 var(--font-sans)
--text-1- rgb(5 5 5 / 0.80)
--text-2- rgb(5 5 5 / 0.60)
--measure- 68ch