# Stepper

The steps of a process, with where the person is. A step is drawn as done only when the app says `done`; pressing a step opens it (through `onStepSelect`) and never completes it. The tick is drawn, and the rail after it filled, when `done` turns true while the stepper is on screen; steps that were already done when it appeared are still. Nothing is current until you set `current`.

- Registry name: `stepper` (`@candor/stepper`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/stepper

## Install

```bash
npx candor-ui add stepper
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/stepper`.
It brings in: locale, locked, motion, utils.

## Example

```tsx
"use client"

import * as React from "react"
import { Stepper, type StepperStep } from "@/components/ui/stepper"
import { Button } from "@/components/ui/button"

// What each step has really been through is the app's data: "done" is set by the save, not by pressing the step.
export default function Example() {
  const [current, setCurrent] = React.useState("details")
  const [saved, setSaved] = React.useState<string[]>([])
  const steps: StepperStep[] = [
    { id: "details", title: "Details", description: "Name and region", done: saved.includes("details") },
    { id: "access", title: "Access", description: "Who can open it", done: saved.includes("access") },
    {
      id: "review",
      title: "Review",
      description: "Check before creating",
      locked: saved.includes("details") && saved.includes("access") ? null : "Save Details and Access first.",
    },
  ]
  return (
    <div className="flex max-w-xl flex-col gap-4">
      <Stepper steps={steps} current={current} onStepSelect={setCurrent} label="New project" />
      <div className="flex gap-2">
        <Button
          size="sm"
          variant="outline"
          onClick={() => setSaved((all) => (all.includes(current) ? all : [...all, current]))}
          disabled={current === "review"}
        >
          Save this step
        </Button>
      </div>
    </div>
  )
}
```

## <Stepper>

Props:

- `steps: StepperStep[]`: The steps in order.
- `current?: string | undefined`: The id of the step the person is on. Left out, no step is current and no count shows.
- `onStepSelect?: ((id: string) => void) | undefined`: Called with a step's id when a person presses it. Left out, the steps are plain text, not buttons.
- `orientation?: "horizontal" | "vertical" | undefined` (default `"horizontal"`): Lay the steps out in a row or a column.
- `showCount?: boolean | undefined` (default `true`): Prints "Step 2 of 5" above the steps when `current` is set.
- `label?: string | undefined`: The list's accessible name. Defaults to "Steps".
- `className?: string | undefined`

## Strings (`stepper`)

The fixed words, English by default. Override any of them under `stepper` in `<LocaleProvider strings={{ stepper: { … } }}>`; the table is exported as `stepperStrings`.

- `steps`: Steps
- `count`: Step {current} of {total}
- `done`: Done
- `current`: Current step
- `failed`: Failed
- `upcoming`: Not started

## Types

### StepperStep

One step. What it is and whether it is done come from the app; the stepper never decides either.

```ts
{ /** A stable id, passed to `onStepSelect` and matched against `current`. */ id: string /** The step's name. */ title: React.ReactNode /** A line under the title. */ description?: React.ReactNode | undefined /** True only when the app knows the step is finished (saved, verified, accepted). Pressing a step never sets it. */ done?: boolean | undefined /** True when the app knows the step failed. Dr
```

## Motion

- **done** (mark, draw): The tick is drawn along its path when the app turns a step's `done` on while the stepper is on screen. A step that is already done when the stepper appears shows its tick at once, and pressing a step never completes it.
- **rail** (fill): The line after a step fills towards the next step when that step turns done while the stepper is on screen, never ahead of it. Lines after steps that were done when the stepper appeared are already full.

Set with `--cd-motion-stepper-<moment>-*` in your brand file; the families are in the design reference.

## 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`.
