Reasoning
A collapsible chain of thought.
Use when a model exposes its reasoning separately from its answer and you want the reader to watch it happen without keeping it on screen afterwards.
Reasoning is the one part of a response a reader wants to watch while it happens and almost never wants to keep. So the element expands while streaming is set and collapses when it clears.
Until the reader touches it. Once they expand or collapse it themselves, the automatic behaviour stops for good — the same ownership rule createBottomFollower applies to scrolling, and for the same reason: an interface that keeps re-deciding something the reader has already decided is worse than one that never decided at all. Setting open from script counts as taking control too, since script is acting for a caller who has an opinion.
Quick Start
<r-reasoning label="Thinking"></r-reasoning>const reasoning = document.querySelector('r-reasoning');
reasoning.streaming = true; // expands
reasoning.content += delta; // grows while visible
reasoning.duration = 4200; // "4.2s" beside the label
reasoning.streaming = false; // collapses, unless the reader intervenedranuts/stream already keeps reasoning-delta apart from text-delta, so a view can feed this straight from a snapshot:
reasoning.content = snapshot.blocks
.filter((block) => block.type === 'reasoning')
.map((block) => block.text)
.join('');
reasoning.streaming = !snapshot.done;Details worth knowing
- Sub-second durations render as nothing. A reader cares that it was fast, not that it was 340ms.
- The label pulses while streaming, so a long silent think does not read as a stall.
prefers-reduced-motionturns the animation off without removing the information. - The default slot replaces the rendered text, for a caller that wants
<r-markdown>in the body instead of plain text.
API Reference
Properties
| Property | Type | Default | Description |
|---|---|---|---|
content | string | '' | The reasoning text. Assigning repeatedly is the streaming path. |
streaming | boolean | false | Whether reasoning is still arriving. |
open | boolean | false | Whether the body is expanded. |
label | string | 'Reasoning' | Summary text. |
duration | number | null | null | Milliseconds spent thinking. Hidden below one second. |
sheet | string | '' | CSS injected into the element's shadow DOM. |
A duration that is not a finite, non-negative number reads back as null.
Slots
| Slot | Description |
|---|---|
| (default) | Replaces the rendered text with your own body content. |
Parts
reasoning, summary, marker, label, meta, body, text.
Accessibility
The summary is a real <button type="button"> with aria-expanded, so it is reachable and operable from the keyboard without extra wiring.
See also
- Conversation — mount this as the reasoning row of a transcript
- ranuts/stream — where
reasoning-deltacomes from