Message

Shows one turn of a conversation: an agent turn as flow with no drawn header, a person turn as a bubble at the end of the row.

Examples

A thread with a live turn

Ana
Can Maya Chen get a refund on order 4812?
support-agent

Yes. The order is inside the 30-day window and damaged items are refunded in full, $48.00.

Worked for 14s,14:02model-sfor model-l
Ana
Refund it and draft her a reply.
support-agentRunning

Refunding $48.00 on order 4812 and drafting the reply to Maya.

A message that failed to send

Ana
Send Maya the drafted reply.
Not sent

A turn that failed

support-agentFailed

The model provider stopped answering after 30 seconds.

1 draft saved

Breaks in the thread

From

  • support-agent

    Order 4812 is refundable.

    agentdefault

  • Ana
    Can we refund it?

    user

State

  • support-agentRunning

    Order 4812 is refundable.

    1 draft saved

    live

  • support-agentWaiting on you

    Order 4812 is refundable.

    1 draft saved

    waiting

  • support-agentFailed

    Order 4812 is refundable.

    1 draft saved

    fail

  • support-agentStopped

    Order 4812 is refundable.

    1 draft saved

    stopped

  • support-agent

    Order 4812 is refundable.

    1 draft saved

    donedefault

Reason

  • interrupted

  • compaction

  • handoff

  • day

States

  • Refund it
    Sending

    sending

  • Refund it
    Not sent

    failed

  • Refund it

    sent

Usage

When to use it
Use
A thread shows turns from a person and an agent in order.
Use
The thread needs a marked change: a stop, a compaction, a handoff or a new day.
Not for
A transient notice about the page, not a turn. Use Alert.
Not for
The scrolling container of the whole thread. Use Conversation.
Not for
The agent's answer body with Markdown. Use Response.

Rules

9 rules
Must
Give every agent turn a MessageHeader that carries one MessageStatus. Because the footer hides while the turn is live and the header ends in Failed or Stopped, all read from that one status.
Must
Set a person's turn as a paper bubble at the end of the row, with the frame line; no avatar and no drawn name. Because the bubble at the end against the full-width flow of the agent is what tells the two speakers apart, in grayscale too.
Must
Name the speaker in MessageHeader text on both turns; a person's header is read aloud and not drawn. Because the bubble has no avatar or name beside it, so a screen reader hears the turn with no speaker.
Must
End a stopped turn with MessageStatus state="stopped" and a MessageDivider reason="interrupted", and keep the partial answer. Because a red Alert reads the person's own Stop as a failure, and dropping the partial answer loses work they may need.
Must
Keep a failed message in its row with MessageSendState state="failed" and onRetry. Because a toast fades in seconds and the person has to retype what they wrote.
Must
Pass both models when the answering model differs from the picked one. Because an operator reads a fallback model's answer as the picked model's and misjudges its quality.
Never
Put the agent's turn in a bubble or a frame. It is flow: sections and a footer, with no name line or avatar. Because a bubble squeezes code blocks and tool rows, and a frame around a whole turn nests the approval card and the code wells in a second box.
Never
Put a Working or Paused word, a badge or the model in the agent header. The running tool row is the live state; the model goes in the footer. Because a word in the header and the arc in a row say the same thing twice, and the header word goes stale the moment the turn waits on an approval.
Should
Use the reason's default words, or 2 to 5 words in sentence case: "Handed to Ana", "Back to support-agent".

Accessibility

4 checks
Tab moves to footer actions, bubble buttons and links; turns are not stops.
Enter on Retry in the failed state resends and the button leaves, so repeats cannot double-send.
The turn state and the send state read as words; the wash is never the only quartz.
MessageHeader names the speaker aloud on both turns; an agent's is drawn only when the turn failed or stopped.

Edge cases

8 edge cases
Long message and hash
Wraps at the reading measure; a 40-character hash breaks anywhere.
Narrow screen
Both turns keep a 16px inset; a bubble grows to 85% of the row, and a failed or stopped header keeps one line.
Right to left
The agent flow starts from the right and the bubble moves to the left; the time column stays at the end.
Empty turn
Nothing is drawn; the name is read aloud, and the thread's thinking row shows the first wait.
Slow send
The row stays and says Sending, with no spinner on the text.
Failed send
Keeps the text, washes the row and offers Retry in place.
Reduced motion
The row arc holds still; the row says Running.
Zoom 200%
Sections grow with the text; a drawn header keeps 24px as a minimum.

API

12 props
Message from, kind, size
'agent' | 'user'
AgentTurn name, time, state
string, ReactNode, MessageStatus state default state 'done'
MessageStatus state, label
'live' | 'waiting' | 'fail' | 'stopped' | 'done'
MessageTime
time
MessageBubble variant, kind
default, outline, inverse, ghost, destructive, tinted default 'default'
MessageBubble status
'fail'
MessageBubbleContent render
ReactElement
MessageWorked duration, time, labels
string, ReactNode
MessageModel model, requested
string
MessageSendState state, onRetry
'sending' | 'sent' | 'failed'
MessageDivider reason, kind, render
'interrupted' | 'compaction' | 'handoff' | 'day'
labels
per part default English words

Tokens

12 tokens
--line-frame
oklch(var(--ink-c) / var(--line-frame-alpha))
--line-row
oklch(var(--ink-c) / 0.08)
--line-control
oklch(var(--ink-c) / 0.16)
--fail-text
oklch(51% 0.180 26)
--fail-wash
oklch(94.5% 0.027 26)
--surface-inverse
var(--ink)
--text-inverse
var(--paper)
--type-label
400 14px/16px var(--font-sans)
--type-tag
var(--type-code-sm)
--type-body-sm
380 13px/18px var(--font-sans)
--text-3
oklch(var(--ink-c) / 0.66)
--time-column
12ch

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.