Reasoning

A collapsible reasoning disclosure that tracks streaming state and elapsed duration.

Planning the approach

Check the existing layout, then decide which axis needs centering.

Verifying

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>:

PropTypeDefault
isStreamingboolean
isOpenboolean
setIsOpen(open: boolean) => void
durationnumber | 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.

PropTypeDefault
isStreamingboolean
false
durationnumber
defaultOpenboolean
false
openboolean
onOpenChange(open: boolean) => void
AttributeDescription
data-reasoningThe disclosure root.
data-streamingPresent while isStreaming is true.
data-openPresent while open.
data-closedPresent 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.

PropTypeDefault
childrenReactNode
AttributeDescription
data-reasoning-triggerThe toggle button.
data-openPresent while open.
data-closedPresent while closed.

Reasoning.Content

The collapsible panel. Renders data-reasoning-content. Bold **Header** lines split the text into sections rendered as markdown.

PropTypeDefault
childrenstring | string[]
(required)
keepMountedboolean
false
AttributeValuesDescription
data-reasoning-contentThe panel.
data-openPresent while open.
data-closedPresent while closed.
data-starting-stylePresent on the first open frame (enter transition).
data-ending-stylePresent while the exit animation runs.
--panel-heightmeasured pxThe 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.