Response

Shows an agent's answer as it streams in.

Examples

An answer in its turn

support-agent

Order ord_4812 qualifies for a full refund.

CheckResultTook
Order foundyes0.4s
Inside 30 daysyes, day 30.1s
Damagedreported2.1s

The reply I would send:

text
Hi Maya, I have refunded $48.00 to your original payment method.

A settled answer

Order ord_4812 qualifies for a full refund.

  • Shipped damaged
  • Inside the 30-day window

Mid-stream

Refunds are capped at $200 per order, see the refund pol

With a refund card

Refunding now.

Refund $48.00 on ord_4812Back to Maya Chen on the original payment method

Sizes

  • Refunds are capped at $200 per order.

    defaultdefault

  • Refunds are capped at $200 per order.

    sm

Tag

  • Refunding now.

    Refund $48.00 on ord_4812Back to Maya Chen on the original payment method

    carddefault

  • Refunding now.

    Preparing refund

    waiting

  • Refunding now.

    broken

  • Done. <notes>v2.4</notes>

    unknown

States

  • Refunds are capped at $200 per order.

    settled

  • Refunds are capped at $200 per

    streaming

  • Refunding now.

    Preparing refund

    tag pending

Usage

When to use it
Use
An agent answer arrives as a stream of markdown.
Use
Generated text carries structured cards (a refund, a ticket) inside it.
Not for
The text is the model thinking aloud. Use Reasoning.

Rules

9 rules
Must
Pass the whole text so far as children and keep streaming true until the end. Because any change that is not an append resyncs, so passing a delta replaces the answer with its last chunk.
Must
Register every card in tags with a pending label and a renderer that takes the parsed JSON. Because only registered names open a tag, so an unregistered card prints its raw tag and JSON into the answer.
Must
Define the inlineTags array at module scope or in useMemo. Because a new array each render breaks the memo on every frozen chunk, so the whole answer re-parses on each token.
Should
Write a tag pending label as an -ing verb and its object, two or three words, no ellipsis.
Never
Wrap a streaming Response in aria-live; leave announcements to Conversation. Because a live region reads every paced slice aloud, and Conversation already announces the finished turn.
Never
Add a fake typewriter; pacing already runs on the real stream. Because a second pace holds back text that already arrived and ignores the reduced-motion skip.
Should
Keep maxCodeLines at its default of 40; longer fences get a Show more lines button.
Should
Use size="sm" for side panels; keep default for an answer in a turn. Reasoning sets its own body styles.
Never
Set a Response heading above type-heading-xs. Because display type inside an answer outranks the page and the turn header, so the answer reads as a new page.

Accessibility

5 checks
The root has no role and sets aria-busy while streaming.
Headings render as h3 to h5, below the turn.
Tables render as table with th scope="col".
Links stay inline text links; code and tables scroll by keyboard and touch.
Never put a live region on the answer.

Edge cases

9 edge cases
Long hash or URL
Inline code and links break anywhere; a code block caps at maxCodeLines.
Empty or whitespace
Renders no blocks, so leading newlines draw no empty paragraph.
Table at 160px
Tables scroll on paper and code inside its well; the page does not.
Right to left
Text and lists align right; the quote indent moves to the right edge.
Unsafe link
javascript: and data: links render as plain labels.
Broken JSON in a tag
The value is discarded; raw JSON never reaches the page.
Stream ends with an open tag
The tag resolves as if it timed out; a JSON tag with a viable body keeps its placeholder until the value completes.
Burst over 512 characters
Paces in word-snapped 24ms slices; a non-append text resyncs at once.
Reduced motion or hidden tab
Every delta renders at once.

API

9 props
children
string default required
streaming
boolean default false
pace
boolean default true
tags
Record<string, TagRenderer> default {}
inlineTags
InlineTag[] default []
tagTimeout
number default 8000
maxCodeLines
number default 40
size
'default' | 'sm' default 'default'
showMoreLines
(lines: number) => string default "Show n more lines"

Tokens

14 tokens
--type-body
340 14px/20px var(--font-sans)
--type-body-sm
380 13px/18px var(--font-sans)
--text-1
var(--ink)
--type-heading-xs
400 16px/20px var(--font-sans)
--type-label
400 14px/16px var(--font-sans)
--surface-card
oklch(var(--grey-c))
--type-code
400 13px/20px var(--font-mono)
--type-code-sm
400 12px/16px var(--font-mono)
--type-tag
var(--type-code-sm)
--line-row
oklch(var(--ink-c) / 0.08)
--line-control
oklch(var(--ink-c) / 0.16)
--text-2
oklch(var(--ink-c) / 0.80)
--row
40px
--row-sm
32px

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.