Chain of Thought
Collapsible reasoning timeline that shows how an assistant reached its answer, step by step.
Description
ChainOfThought is a compound disclosure built on Radix Collapsible. A one-line trigger summarizes the reasoning ("Thought for 6 seconds") and opens a timeline of steps. The steps render as an <ol> of <li> elements, each with a marker on a vertical rail, an optional label and free-form content.
Use it inside an assistant message to expose model reasoning, agent traces, research steps or a multi-stage tool run. Set isStreaming while the model is still thinking: the trigger shimmers and the root reports aria-busy. Give each step a status to show what is done, what is running, what failed and what is still queued.
Don't use it for a single tool call with input and output payloads, use ChatTool. For a plain loading line with no steps, use ChatLoader or TextShimmer. For a numbered, user-driven flow such as checkout, use Stepper, and for general expandable page sections use Accordion.
ChainOfThought is a Create UI Pro component. Install it with a Pro seat.
Installation
Anatomy
Usage
Examples
Every example is a Pro preview (marked with a Pro badge).
Step status
status sets the marker and text tone of a step. complete is the default, active pulses the dot and shimmers the label, pending draws a hollow dot and error turns the marker and label red. Put the outcome in the label text too ("Migration failed"), since color alone is not announced.
Step icons
icon replaces the dot with a glyph on the rail, sized to 16px and tinted by status. Use it when the kind of step matters more than its order: search, browse, write code.
Trigger icon
icon on ChainOfThoughtTrigger adds a leading glyph that stays solid while the text shimmers. A long summary truncates with an ellipsis instead of pushing the chevron off the line.
Controlled
Pass open and onOpenChange to drive the disclosure from your own state, for example to collapse every reasoning block when a new message arrives. Leave both off and use defaultOpen for the uncontrolled case.
Streaming
isStreaming shimmers the trigger and sets aria-busy on the root. Move status="active" down the list as steps finish, then flip isStreaming off and close the block. The tree stays mounted the whole time, so nothing jumps when reasoning ends.
Nested
Steps accept any content, including another ChainOfThought or a second ChainOfThoughtSteps. Each nested timeline keeps its own rail. Tighten a dense list with the --chain-of-thought-step-gap variable on ChainOfThoughtSteps.
Accessibility
The trigger is a native <button> from Radix Collapsible, so it is focusable and toggles with the keyboard. The steps are plain content with no interactive parts of their own.
ARIA notes:
- Radix sets
aria-expandedandaria-controlson the trigger and links it to the content region. - The root sets
aria-busy="true"whileisStreamingis on and removes it when streaming ends. - Steps render as
<ol>and<li>, so screen readers announce the step count and position. - The step with
status="active"getsaria-current="step". Other statuses are visual only, so say "failed" or "skipped" in the label when it matters. - The chevron, the trigger icon and the step rail (dot, icon and connector) are
aria-hidden. - The focus outline is a 2px
outline-strongoffset by 2px, never a ring. - The open and close animation and the active dot pulse are skipped under
prefers-reduced-motion.TextShimmeralso stops its sweep there. - See the Radix Collapsible docs for the full disclosure behavior.
Styling
Tailwind override: pass className to any part. On the root it sets width and spacing, on the trigger it adjusts color or height, and on ChainOfThoughtSteps it can change the gap between steps:
Data slots and attributes: the component sets these for CSS targeting:
data-slot="chain-of-thought"on the root, withdata-status("streaming"or"complete") and the Radixdata-state("open"or"closed") anddata-disabled.data-slot="chain-of-thought-trigger"on the button, withdata-stateanddata-disabled.data-slot="chain-of-thought-trigger-icon"on the leading icon wrapper, wheniconis set.data-slot="chain-of-thought-trigger-label"on the text wrapper. The shimmer inside it carriesdata-slot="text-shimmer"anddata-active.data-slot="chain-of-thought-trigger-indicator"on the chevron.data-slot="chain-of-thought-content"on the collapsible region, withdata-state, anddata-slot="chain-of-thought-content-body"on its padded inner wrapper.data-slot="chain-of-thought-steps"on the<ol>.data-slot="chain-of-thought-step"on each<li>, withdata-status("pending","active","complete"or"error").data-slot="chain-of-thought-step-rail"on the marker column, holdingdata-slot="chain-of-thought-step-indicator"(the 16px marker box),data-slot="chain-of-thought-step-dot"(the default dot, absent wheniconis set) anddata-slot="chain-of-thought-step-connector"(the line to the next step, hidden on the last one).data-slot="chain-of-thought-step-body",data-slot="chain-of-thought-step-label"anddata-slot="chain-of-thought-step-content"on the text column.
CSS variables: --chain-of-thought-step-gap sets the space below each step body, which is also how far the connector runs. It defaults to 0.75rem. Don't use gap-* on ChainOfThoughtSteps: a gap breaks the rail between steps. Radix also exposes --radix-collapsible-content-height on the content for the open and close animation.
Related Components
- Chat Tool: a single tool call with its input, output and status, rather than a reasoning timeline.
- Chat Loader: a loading line or dots while the assistant has nothing to show yet.
- Text Shimmer: the shimmer used by the trigger, on its own for a status line.
- Stepper: a numbered flow the user moves through, not a log of what the model did.
- Accordion: general expandable sections on a page.
API Reference
ChainOfThought
The root. Wraps Radix Collapsible.Root, so it accepts every Collapsible root prop and any <div> attribute.
Props
Variants
The root has no variant axis. chainOfThoughtVariants() returns its base classes (w-full min-w-0 text-paragraph-xs).
ChainOfThoughtTrigger
The summary line and toggle. Wraps Radix Collapsible.Trigger and renders a <button>, so any button attribute is accepted.
Props
Variants
Set from the root's isStreaming, not as a prop. Exported as chainOfThoughtTriggerVariants.
ChainOfThoughtContent
The collapsible region. Wraps Radix Collapsible.Content and animates its height open and closed.
Props
ChainOfThoughtSteps
The timeline list. Extends React.ComponentProps<"ol">.
Props
ChainOfThoughtStep
One entry on the rail. Extends React.ComponentProps<"li">.
Props
Variants
Exported as chainOfThoughtStepIndicatorVariants, applied to the marker box.