Reasoning

Shows the model's reasoning as it thinks, then folds it away.

Examples

While the model thinks

support-agentRunning

Checking the refund window

The policy allows 30 days and the order shipped 3 days ago.

Folded once it answers

support-agent

Order 4812 is inside the 30-day window, so it qualifies for a refund.

Opened to read

support-agent

Checking the refund window

The policy allows 30 days and the order shipped 3 days ago.

Order 4812 is inside the 30-day window, so it qualifies for a refund.

States

  • Checking the refund window

    The policy allows 30 days and the order shipped 3 days ago.

    streaming

  • folded

  • Checking the refund window

    The policy allows 30 days and the order shipped 3 days ago.

    open

  • stopped

Usage

When to use it
Use
The model streams reasoning before or between answer parts.
Use
The person may want to read how the answer was reached, but not by default.
Not for
The answer itself. Use Response.
Not for
Any other fold-away section. Use Collapsible.

Rules

7 rules
Must
Pass summary parts as an array of children, not a joined string. Because the label takes the first heading of the newest part, so a joined string keeps the first heading for the whole stream.
Must
Leave open unset and pass streaming; the block opens while it streams and folds at the end. Because a controlled open turns off the fold and the pin, so a block the person opened snaps shut when the stream ends.
Must
Show a live Reasoning only on the active turn. Because every streaming block opens and reads "Thinking", so finished turns look busy and push their answers down.
Should
Pass duration in seconds when the stream ends so it reads "Thought for 12s".
Never
Put reasoning in a live region. The body carries aria-busy and the label stays the button name. Because a live region reads every paced slice aloud and cuts off the answer that follows.
Never
Render reasoning as a Response above the answer. Keep it in text-2 at body-sm in its row's panel. Because ink at answer size reads as the answer, so the person acts on a draft the model later dropped.
Should
Keep the body at 160px and let it scroll; do not set max-h-none.

Accessibility

5 checks
Enter or Space on the trigger opens or folds the body; opening pins it.
The body carries aria-busy while streaming; the label stays the button name.
Tab focuses an overflowing body so arrows scroll it; Up releases the follow.
The trigger is a 32px row across the turn, the same line as a folded group of tool calls; a touch scroll up in the body stops the follow.
Reduced motion stops the running arc; open and fold are cuts already.

Edge cases

9 edge cases
Long heading
Truncates in the row; long text scrolls inside 160px with a thin scrollbar, no fade.
Right to left
The chevron stays in the leading cell, at the start edge, and mirrors.
One word
Opens a one-line body.
Empty streaming text
Shows "Thinking" with an empty body; a stream stopped before text folds to "Stopped".
Long pause
Stays open with the last heading.
Turn fails
Streaming ends and the block folds; the error belongs to Conversation.
Ten presses on the trigger while streaming
It ends in the last state the person chose.
Inside a Message above a Response
The nested scroller lets the thread detach only at overscroll.
120px wide
The trigger truncates its label and the body wraps.

API

6 props
children
string | string[] | parts
streaming
boolean default false
duration
number
heading
string default from the text
open, defaultOpen, onOpenChange
Collapsible
labels
{thinking?, stoppedEarly?, thoughtFor?, moment?} default English words

Tokens

7 tokens
--type-label
400 14px/16px var(--font-sans)
--type-body-sm
380 13px/18px var(--font-sans)
--text-2
oklch(var(--ink-c) / 0.80)
--surface-hover
oklch(var(--ink-c) / 0.05)
--row-sm
32px
--dur-fast
120ms
--ease-step
cubic-bezier(0.2, 0, 0, 1)

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.