Reasoning Steps

AI reasoning trace with a shimmering trigger label, a self-timing readout, and a connected step timeline.

Installation

npx shadcn@latest add @iconiq/reasoning-steps

File Structure

Usage

import {
  ReasoningStep,
  ReasoningStepDetails,
  ReasoningStepSource,
  ReasoningStepSources,
  ReasoningSteps,
  ReasoningStepsContent,
  ReasoningStepsTrigger,
} from "@/components/ui/reasoning-steps";

export function AssistantReply() {
  return (
    <ReasoningSteps>
      <ReasoningStepsTrigger>Reasoning</ReasoningStepsTrigger>
      <ReasoningStepsContent>
        <ReasoningStep
          description="Parsing the question and pulling out the actual constraints."
          label="Reading the request"
          status="done"
        />
        <ReasoningStep
          description="Checking the deploy config mentioned earlier in the thread."
          label="Recalling relevant context"
          status="done"
        />
        <ReasoningStep
          description="A quick rollback versus a targeted env-var fix."
          label="Weighing two approaches"
          status="done"
        >
          <ReasoningStepDetails summary="See the tradeoffs">
            A rollback restores service in under a minute but loses the
            config fix for the next deploy. The env-var patch takes longer
            to verify but fixes it at the source.
          </ReasoningStepDetails>
          <ReasoningStepSources>
            <ReasoningStepSource>vercel.com/docs</ReasoningStepSource>
            <ReasoningStepSource>runbook.md</ReasoningStepSource>
          </ReasoningStepSources>
        </ReasoningStep>
        <ReasoningStep
          description="Writing the fix as a short, ordered checklist."
          label="Drafting the answer"
          status="active"
        />
      </ReasoningStepsContent>
    </ReasoningSteps>
  );
}

Props

Props
Description

ReasoningSteps

children

Composition surface. Place a ReasoningStepsTrigger followed by a ReasoningStepsContent inside.

Type ReactNode

duration

Elapsed reasoning time in seconds, shown in the trigger once greater than 0. Omit to let the root time itself for as long as any mounted step has status "active".

Type number

defaultOpen

Initial open state for uncontrolled usage.

Type boolean·Default false

open

Controlled open state. Pair with onOpenChange to drive the panel yourself.

Type boolean

onOpenChange

Called when the trigger is clicked.

Type (open: boolean) => void

className

Extra classes for the outer card.

Type string

ReasoningStep

label

Step heading shown in the timeline and the collapsed preview.

Type ReactNode

status

The in-flight step should be "active"; steps not yet reached should be omitted or "pending", which renders nothing.

Type "pending" | "active" | "done"·Default "done"

description

Muted supporting copy under the label.

Type ReactNode

id

Stable identity used for the root's registry. Auto-generated when omitted.

Type string

children

Nest ReasoningStepDetails and/or ReasoningStepSources under a step's description.

Type ReactNode

className

Extra classes for the row.

Type string

ReasoningStepDetails

summary

Always-visible trigger label, e.g. "See the tradeoffs".

Type ReactNode

defaultOpen

Initial open state.

Type boolean·Default false

ReasoningStepsTrigger

The disclosure row: just the label and the elapsed-seconds readout — no status icon and no chevron. children defaults to "Reasoning".

No icon runs next to the label. Instead, the label itself gets a looping shimmer sweep clipped to the text while any step is active, and settles to plain text once nothing is in flight.

While collapsed, a small preview line beneath the label slides and blurs between step labels as the active step changes, so the current step stays visible without opening the panel.

ReasoningStepsContent

The panel: renders its ReasoningStep children in a ul and measures its own natural height with a ResizeObserver instead of animating to Motion's "auto", so the spring never overshoots under a scaled ancestor.

The connecting line under a step is only drawn between rendered steps — it's hidden automatically on whichever step ends up last, with no isLast bookkeeping required from the consumer.

ReasoningStepSources, ReasoningStepSource, ReasoningStepImage

Optional citation and attachment parts for a step. Sources wraps a row of Source pills in a flex-wrap container; each Source blurs and scales in and renders as a link when given href. Image blurs in an attached screenshot or diagram with an optional caption.

ReasoningStepSource renders an anchor when href is passed (opened in a new tab) and a plain span otherwise.

Registry bundle

Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.

Dependencies: @base-ui/react, motion, lucide-react.

Contact

Additionally, if you find any bug or issue, feel free to raise an issue.

Why did my staging deploy fail?