ChainOfThought

free

A compact record of the reasoning behind a response for readers who need more context.

Preview
Dark

The request is clear, so the response can focus on the two implementation constraints.

import ChainOfThought from '@/components/composites/ChainOfThought';

export default function UsageDemo() {
  return (
    <div className="w-full max-w-xl">
      <ChainOfThought defaultExpanded>
        <p>
          The request is clear, so the response can focus on the two
          implementation constraints.
        </p>
      </ChainOfThought>
    </div>
  );
}

Installation

Add this component with the NateUI CLI.

npx nateui@latest add ChainOfThought

Examples

Labeled Steps

Preview
Dark
Read the request
Identify the required behavior and the boundaries around it.
Check the existing surface
Reuse the project primitives that already own disclosure and text motion.
Choose the smallest change
Keep the timeline local to this component so it stays independent.
import ChainOfThought from '@/components/composites/ChainOfThought';
import { PiCheckCircle, PiClipboardText, PiSparkle } from 'react-icons/pi'

export default function LabeledStepsDemo() {
  return (
    <div className="w-full max-w-xl">
      <ChainOfThought defaultExpanded label="Review trace">
        <ChainOfThought.Step
          icon={<PiClipboardText />}
          label="Read the request"
        >
          Identify the required behavior and the boundaries around it.
        </ChainOfThought.Step>
        <ChainOfThought.Step
          icon={<PiSparkle className="text-primary" />}
          label="Check the existing surface"
        >
          Reuse the project primitives that already own disclosure and text
          motion.
        </ChainOfThought.Step>
        <ChainOfThought.Step
          icon={<PiCheckCircle className="text-success" />}
          label="Choose the smallest change"
        >
          Keep the timeline local to this component so it stays independent.
        </ChainOfThought.Step>
      </ChainOfThought>
    </div>
  );
}

Streaming

Set isStreaming while content is arriving. The disclosure opens immediately, shimmers its label, and closes after the stream settles unless the reader toggles it.

Preview
Dark
import { useEffect, useState } from 'react';
import ChainOfThought from '@/components/composites/ChainOfThought';
import Button from '@/components/ui/Button';

export default function StreamingDemo() {
  const [isStreaming, setIsStreaming] = useState(false);

  useEffect(() => {
    if (!isStreaming) return;

    const timeout = window.setTimeout(() => {
      setIsStreaming(false);
    }, 2200);

    return () => window.clearTimeout(timeout);
  }, [isStreaming]);

  return (
    <div className="w-full max-w-xl space-y-4">
      <Button
        size="sm"
        onClick={() => setIsStreaming(true)}
        disabled={isStreaming}
      >
        Start trace
      </Button>
      <ChainOfThought isStreaming={isStreaming}>
        <ChainOfThought.Step label="Working">
          The trace stays open while the next step is being prepared.
        </ChainOfThought.Step>
      </ChainOfThought>
    </div>
  );
}

API

ChainOfThought

PropDescriptionTypeDefault
isStreamingForces the disclosure open while content is arriving, shimmers the label, and starts the settle timer when the stream ends.booleanfalse
defaultExpandedOpens the disclosure on its first render when it is not streaming.booleanfalse
labelReplaces the default streaming or settled trigger label.string'Thinking…' while streaming; 'Thought process' otherwise
classNameClasses merged onto the disclosure root.string
childrenPlain content or ChainOfThought.Step rows rendered in the disclosure rail.ReactNode

ChainOfThought.Step

PropDescriptionTypeDefault
iconReplaces the default dot in the step's marker slot.ReactNodeDot marker
labelOptional heading for the step.ReactNode
childrenOptional supporting content rendered below the label.ReactNode
classNameClasses merged onto the step row.string
...divPropsStandard <div> attributes forwarded to the step row.ComponentProps<'div'>