# Stepper

**When to use:** Step progress indicator for multi-step forms, onboarding flows, and checkout wizards. Shows completed, current, and upcoming steps, and (vertically) can expand a collapsible body under the active step.

**Keywords:** wizard steps, progress steps

**Import:** `import { Stepper, StepperOrientation, StepperStyleType, StepperCollapse, StepperLabelPlacement, ThemeColor } from '@ahrowe/ui'`
**Types:** `import type { StepperStep, StepperProps, StepperLabels } from '@ahrowe/ui'`

**Enums:**
- `StepperOrientation`: `Horizontal` (default) | `Vertical`
- `StepperStyleType`: `Filled` (default: completed markers filled solid) | `Outlined` (completed markers stay ringed, with a check in the colour) | `Dots` (minimal dots, no numbers)
- `StepperCollapse`: `None` (default) | `ActiveOnly` | `Completed`
- `StepperLabelPlacement`: `Top` | `Bottom` | `Left` | `Right`

**Colours:** any `color`: a `ThemeColor` (default `Primary`) or any CSS colour, see [ThemeColor.md](ThemeColor.md). It paints the current and completed markers and the connectors between them. Upcoming steps are drawn in the theme's `--border-color` and `--text-dark`, and a step with `error` in its `--error-color`.

```tsx
import { Stepper, StepperOrientation, StepperStyleType, StepperCollapse, ThemeColor } from '@ahrowe/ui';
import { faUser, faCreditCard } from '@fortawesome/free-solid-svg-icons';

const steps = [
  { label: 'Account' },
  { label: 'Profile' },
  { label: 'Confirm' },
];

// Horizontal (default)
<Stepper steps={steps} currentStep={1} />

// Style presets and colour
<Stepper steps={steps} currentStep={1} styleType={StepperStyleType.Outlined} />
<Stepper steps={steps} currentStep={1} styleType={StepperStyleType.Dots} hideLabels />
<Stepper steps={steps} currentStep={1} color={ThemeColor.Success} />

// Vertical, clickable
<Stepper
  steps={steps}
  currentStep={currentStep}
  orientation={StepperOrientation.Vertical}
  onStepClicked={(stepIndex) => setCurrentStep(stepIndex)}
/>

// Rich steps: icon, description, error, optional
<Stepper
  currentStep={2}
  steps={[
    { label: 'Account', icon: faUser, description: 'Login details' },
    { label: 'Payment', icon: faCreditCard, error: true },
    { label: 'Review', optional: true },
  ]}
/>

// Vertical wizard with collapsible bodies (only the active step's body is open)
<Stepper
  orientation={StepperOrientation.Vertical}
  collapse={StepperCollapse.ActiveOnly}
  currentStep={step}
  onStepClicked={setStep}
  steps={[
    { label: 'Account', description: 'Login details', content: <AccountForm /> },
    { label: 'Profile', description: 'About you',      content: <ProfileForm /> },
    { label: 'Confirm', description: 'Finish',         content: <ConfirmStep /> },
  ]}
/>
```

**StepperStep:**

| Field | Type | Description |
|-------|------|-------------|
| `label` | `ReactNode` | Primary step label |
| `description` | `ReactNode` | Secondary line under the label |
| `content` | `ReactNode` | Collapsible body under the label (vertical only) |
| `icon` | `IconDefinition \| ReactElement` | Icon in the marker, replacing the number — FontAwesome icon or any React element |
| `error` | `boolean` | Draws the marker in `--error-color`, suppresses the checkmark, and tells screen readers |
| `optional` | `boolean \| ReactNode` | `true` → the `optional` label as a hint; a node → custom hint text |
| `disabled` | `boolean` | Never clickable, dimmed |

**Key props:**

| Prop | Type | Description |
|------|------|-------------|
| `steps` | `StepperStep[]` | The steps to render |
| `currentStep` | `number` | Zero-based index of the current step. `steps.length` marks every step completed |
| `orientation` | `StepperOrientation` | Direction the steps run in (default `Horizontal`) |
| `styleType` | `StepperStyleType` | How the markers are drawn (default `Filled`) |
| `color` | `ColorValue` | A `ThemeColor` (default `Primary`) or any CSS colour |
| `collapse` | `StepperCollapse` | Which `content` bodies are expanded. Vertical only (default `None`) |
| `labelPlacement` | `StepperLabelPlacement` | Label position; default `Bottom` (horizontal) / `Right` (vertical). An out-of-orientation value falls back to that default |
| `onStepClicked` | `(stepIndex: number) => void` | Navigate on step click. Linear: only completed steps are clickable; with `nonLinear`, any enabled step except the current one. A clickable step is a `<button>`, and so is the current one, `aria-disabled`, so focus stays on a step after activating it |
| `nonLinear` | `boolean` | Allow clicking any step, not just completed ones |
| `hideLabels` | `boolean` | Hide each step's label, description and hint visually. Screen readers still read them, and vertical `content` still shows |

**Layout:** a horizontal stepper gives every step an equal share of its width, with the marker centred in it and the label wrapping within it, so a long label never reaches past the stepper or into its neighbour. The connectors run from marker to marker.

**Collapse (vertical `content`):** `None` keeps every body open; `ActiveOnly` opens just the current step's body (classic vertical wizard); `Completed` collapses completed bodies while keeping the current and upcoming ones open. A collapsed body is `inert`, so nothing in it can be focused. Bodies animate their height and respect `prefers-reduced-motion`. Horizontal steppers don't render inline `content` and ignore `collapse`.

**Accessibility:** the stepper is an ordered list, the current step carries `aria-current="step"`, and every other step's status is read out from the `completed`, `notCompleted` and `error` labels. The marker is hidden from screen readers: the list gives the position.

**Labels:** `optional` `completed` `notCompleted` `error` — the text this component renders of its own; the last three are for screen readers only. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `StepperLabels`.

**Theming:** these are theme variables (typed on `ThemeVariables`). Set them theme-wide via `ThemeProvider`'s `variables`, or per instance via `style`, without fighting specificity. Each falls back to a built-in default when unset:

| Variable | Falls back to |
|----------|---------------|
| `--stepper-marker-size` | `40px` |
| `--stepper-marker-radius` | `var(--default-border-radius)` |
| `--stepper-connector-thickness` (completed connectors) | `3px` |
| `--stepper-connector-idle-thickness` (not-yet-reached connectors) | `1px` |
| `--stepper-gap` | `12px` |

```tsx
// Theme-wide, via ThemeProvider: circular markers, thicker connectors
const theme: Theme = {
  id: 'brand',
  variables: {
    '--stepper-marker-radius': '50%',
    '--stepper-connector-thickness': '4px',
  },
};

// Or one-off on a single stepper via style
<Stepper
  steps={steps}
  currentStep={1}
  style={{ '--stepper-marker-radius': '50%' } as React.CSSProperties}
/>
```

**Slots:** `root` `entry` `entryNumber` `entryLabel` `connector` `description` `content` `optional` `icon`

## Migration from `alignment`, `StepperStyleType.Default` and the colour variables

Before 0.45, a Stepper's direction was `alignment`, its default look `StepperStyleType.Default`, and
its colours six theme variables. TypeScript points at the first two:

| Before | After |
|--------|-------|
| `alignment={StepperAlignment.Vertical}` or `alignment='vertical'` | `orientation={StepperOrientation.Vertical}` |
| `alignment={StepperAlignment.Horizontal}` | nothing: `Horizontal` is the default |
| `styleType={StepperStyleType.Default}` | nothing: `Filled` is the default |

**The colour variables compile unchanged and do nothing**, since a theme accepts any variable:

| Theme set | Instead |
|-----------|---------|
| `--stepper-active-color`, `--stepper-done-color`, `--stepper-connector-color` | `color`, on the instance or app-wide with `defaultProps={{ Stepper: { color: 'var(--your-colour)' } }}` |
| `--stepper-text-on-marker` | nothing: it is picked for contrast with `color` (`--text-on-primary` for `Primary`) |
| `--stepper-error-color` | `--error-color` |
| `--stepper-idle-color` | `--border-color` and `--text-dark` theme-wide, or `classNames.entryNumber` for the Stepper alone |

Three more changes compile unchanged and need a look of their own:

- **Horizontal steps take equal columns**, so the first and last markers no longer sit at the
  stepper's edges. A `styles.connector` or `classNames.connector` that sized the connector (such as
  `{ flex: 1, width: 'auto' }`) is no longer needed: the connector is positioned between the markers.
- **`hideLabels` no longer hides vertical `content`**, and keeps the labels for screen readers.
- **A clickable step is a `<button>`**, not a `div` with `role="button"`. CSS that selected
  `[role="button"]` inside a Stepper should select `button`.
