# Step list

An ordered list of steps joined by a rail: an agent's plan, its reasoning, a run's stages. The rail fills to each step as it finishes, never ahead of it, and a step that finishes while on screen draws its mark.

- Registry name: `step-list` (`@candor/step-list`)
- Tier: Free (MIT). No licence key needed.
- Docs: https://candor.themethodic.com/docs/step-list

## Install

```bash
npx candor-ui add step-list
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/step-list`.
It brings in: status, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import { StepList, type Step } from "@/components/step-list"

const steps: Step[] = [
  { id: "1", title: "Read the order history", status: "succeeded", meta: "3s" },
  { id: "2", title: "Draft the refund", status: "succeeded", meta: "5s", detail: "$42.00 to the original card" },
  { id: "3", title: "Ask a person to approve", status: "waiting" },
  { id: "4", title: "Issue the refund", status: "idle" },
]

export default function Example() {
  return <StepList steps={steps} className="max-w-md" />
}
```

## <StepList>

Props:

- `steps: Step[]`: The steps in order, each with a status, and optional detail and meta.
- `className?: string | undefined`

## <StepMark>

A step's status as a mark. When the status reaches done or failed while the mark is on screen, the spinner becomes a tick or cross drawn along its path; a mark that mounts already finished is drawn still.

Props:

- `status: RunStatus`: The step's status, which picks its mark.

## Types

### Step

```ts
{ id: string title: React.ReactNode status: RunStatus detail?: React.ReactNode | undefined meta?: React.ReactNode | undefined }
```

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider` (fixed strings) and `TermsProvider` (nouns); entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
