Reasoning
A collapsible reasoning disclosure that tracks streaming state and elapsed duration.
Check the existing layout, then decide which axis needs centering.
Confirm the element centers both horizontally and vertically.
Usage guidelines
- Chain-of-thought disclosure — a collapsible block for a model's thinking.
- Live label — shimmers "Thinking…" while streaming and settles to "Thought for Ns" when it stops; the duration is tracked for you.
- Sectioned content — bold
**Header**lines split the text into labelled sections, rendered as markdown. - State via
useReasoning— read streaming, open, and duration from anywhere inside. - Get started — see Quick start to add the package.
Anatomy
<Reasoning.Root isStreaming={isStreaming}>
<Reasoning.Trigger />
<Reasoning.Content>{reasoningText}</Reasoning.Content>
</Reasoning.Root>Driven from a streaming message, passing the reasoning parts' text:
<Reasoning.Root isStreaming={isLast && isStreaming} defaultOpen={false}>
<Reasoning.Trigger label={headers} />
<Reasoning.Content>{texts}</Reasoning.Content>
</Reasoning.Root>useReasoning
Read the disclosure state from anywhere inside <Reasoning.Root>:
| Prop | Type | Default |
|---|---|---|
isStreaming | boolean | — |
isOpen | boolean | — |
setIsOpen | (open: boolean) => void | — |
duration | number | undefined | — |
Accessibility
Built on a disclosure: Reasoning.Trigger is a <button> with aria-expanded
and aria-controls pointing at the panel, so screen readers announce the
collapsed/expanded state and the relationship. While isStreaming, the root
carries aria-busy so assistive tech knows the content is still updating.
API reference
Every part accepts className, style, and render (see
Styling) and emits a bespoke part attribute (data-<part>) unless noted.
Reasoning
The disclosure root. Renders data-reasoning.
| Prop | Type | Default |
|---|---|---|
isStreaming | boolean | false |
duration | number | — |
defaultOpen | boolean | false |
open | boolean | — |
onOpenChange | (open: boolean) => void | — |
| Attribute | Description |
|---|---|
data-reasoning | The disclosure root. |
data-streaming | Present while isStreaming is true. |
data-open | Present while open. |
data-closed | Present while closed. |
Reasoning.Trigger
The toggle. Renders a <button> with data-reasoning-trigger. It ships no
copy — supply the label as children, and read isStreaming and duration from
useReasoning() if you want it to change while thinking.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | — |
| Attribute | Description |
|---|---|
data-reasoning-trigger | The toggle button. |
data-open | Present while open. |
data-closed | Present while closed. |
Reasoning.Content
The collapsible panel. Renders data-reasoning-content. Bold **Header**
lines split the text into sections rendered as markdown.
| Prop | Type | Default |
|---|---|---|
children | string | string[] | (required) |
keepMounted | boolean | false |
| Attribute | Values | Description |
|---|---|---|
data-reasoning-content | — | The panel. |
data-open | — | Present while open. |
data-closed | — | Present while closed. |
data-starting-style | — | Present on the first open frame (enter transition). |
data-ending-style | — | Present while the exit animation runs. |
--panel-height | measured px | The content's natural height, published only while the open or close transition runs so a height transition has a number to animate from. Deliberately released once it settles open, which makes `height: var(--panel-height)` fall back to `auto` so the open panel tracks reasoning text as it streams in. |