Skip to documentation content

Thinking State

Show that an agent is working, and keep its steps, reasoning, searches, and sources one press away.

thinking-state-demo

Overview

Thinking State is a one-line header that says what the agent is doing, with a trace behind it. While the agent works, the header shimmers and the trace is open so new rows are visible as they arrive. When the work settles, the trace closes and the header becomes a quiet summary that still opens on request.

Take a question that needs a web search. The header reads "Searching the web" while the query and the sources appear under it. When the search ends, you change the label to "Read 2 sources" and set the status to done. The trace closes, and the person can reopen it to see what was read.

Thinking State does not run anything and does not keep time. You pass the status, the label, and the rows. Use Tool Chips instead when the run is mostly tool calls with output and file changes.

Anatomy

ThinkingState
  • ThinkingStateThe header and the disclosure that holds the trace
    • ThinkingStepOne step of work, with a running, done, or failed mark
    • ThinkingTextA paragraph of reasoning
    • ThinkingQueryA search the agent ran
    • ThinkingSourceA page the agent read, as a link

The four row types can be mixed in any order. Installing thinking-state brings Collapsible and Text Shimmer along as registry dependencies.

Behavior

Status

status is running, done, or error. Running shimmers the label. Done sets it in the secondary text color. Error replaces the header icon with an alert icon in the danger color and sets the label in the primary text color, so it stays readable.

Open and closed

Without open or defaultOpen, the trace is open while the status is running and closed otherwise. Once the person opens or closes it, their choice stays, whatever the status does next. Pass defaultOpen to choose the starting state yourself, or open and onOpenChange to control it.

With no children, the header is plain text with no disclosure.

New rows

A row that is added while the trace is open fades in. Rows keep their position, so nothing above the new row moves.

Accessibility

The header is a button that reports whether the trace is expanded. The trace is a list, and each row is a list item.

When label changes, the new label is announced through a polite status region. The first label is not announced, because it is already in the reading order.

Each step ends with words for its status, read only by screen readers: "In progress", "Done", or "Failed". Pass statusLabel to change them. The query row is read with "Searched for" before it. Icons are decorative.

With reduced motion, the shimmer stops, the spinner does not rotate, and rows appear without fading.

ThinkingSource renders a link and passes other anchor props through. If you open sources in a new tab, say so in the link's name.

KeyAction
TabMove to the header, then to each source link in an open trace
Enter or SpaceOpen or close the trace

Installation

npx honestui@latest add https://ai.honestui.com/r/thinking-state.json

Usage

Set the status and the label from your agent's state, and render one row for each event you have received:

import { ThinkingState, ThinkingStep } from "@/components/ai/thinking-state"

<ThinkingState
  status={run.isFinished ? "done" : "running"}
  label={run.isFinished ? `Finished ${run.steps.length} steps` : "Thinking"}
>
  {run.steps.map((step) => (
    <ThinkingStep key={step.id} status={step.status} detail={step.detail}>
      {step.title}
    </ThinkingStep>
  ))}
</ThinkingState>

Write the settled label as a result. "Read 2 sources" tells the person more than "Done".

Examples

Search and sources

A settled search, open from the start. The sources are real links.

thinking-state-search

A failed run

Set the status to error on the header and on the step that failed, and say what happened in the label.

thinking-state-error

API reference

ThinkingState

Accepts native div props beyond those listed.

PropTypeDefaultDescription
status"running" | "done" | "error"RequiredWhat the agent is doing now.
labelstringRequiredThe header text. Announced when it changes.
iconReactNodeSparkles iconReplaces the header icon. The error status always shows the alert icon.
openbooleanNoneControls whether the trace is shown.
defaultOpenbooleanFollows statusThe initial open state.
onOpenChange(open: boolean) => voidNoneRuns when the person opens or closes the trace.

ThinkingStep

Accepts native li props beyond those listed.

PropTypeDefaultDescription
status"running" | "done" | "error""done"The mark shown before the step.
detailReactNodeNoneSecondary text after the step.
detailIsCodebooleanfalseSets detail in the monospace face.
statusLabelstringEnglishThe words read for the status.

ThinkingText

Accepts native li props. Its children are the paragraph.

ThinkingQuery

Accepts native li props beyond those listed. Its children are the query.

PropTypeDefaultDescription
prefixstring"Searched for"Read before the query by screen readers.

ThinkingSource

Accepts native anchor props beyond those listed.

PropTypeDefaultDescription
hrefstringRequiredThe page that was read.
titleReactNodeRequiredThe page or site name.
domainstringNoneThe host, shown after the title.