# Stepper

An accessible React stepper for Next.js and Tailwind CSS: the steps of a checkout or setup, with a line that fills as you advance and checks that draw in.

Source: https://ui.fewtone.com/components/stepper

## Installation

```bash
npx shadcn@latest add https://ui.fewtone.com/r/stepper.json
```

## Usage

```tsx
import {
  Stepper,
  StepperIndicator,
  StepperItem,
  StepperSeparator,
  StepperTitle,
  StepperTrigger,
} from "@/components/ui/stepper"

const steps = ["Cart", "Shipping", "Payment"]

export function Checkout() {
  return (
    <Stepper defaultValue={2} aria-label="Checkout">
      {steps.map((title, index) => (
        <StepperItem key={title} step={index + 1}>
          <StepperTrigger>
            <StepperIndicator />
            <StepperTitle>{title}</StepperTitle>
          </StepperTrigger>
          <StepperSeparator />
        </StepperItem>
      ))}
    </Stepper>
  )
}
```

## API reference

### Stepper

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number` | – | The current step, from 1, when you control it. Past the last step, every step is done. |
| `defaultValue` | `number` | `1` | The current step at first. |
| `onValueChange` | `(value: number) => void` | – | Called with the step a trigger was pressed for. |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | A row with the lines between the steps, or a column with the lines down the side. |

### StepperItem

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `step` | `number` | – | Its place in the task, from 1. |
| `completed` | `boolean` | – | Done or not, whatever the current step. Left out, the steps before the current one are done. |
| `disabled` | `boolean` | `false` | Its trigger can't be pressed, for example a step that isn't reachable yet. |

### StepperTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Render the single child instead, for example a link to the step's page. |

### StepperIndicator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### StepperTitle

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### StepperDescription

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### StepperSeparator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

**When to use it:** Use Stepper to show where someone is in a task with a fixed order of steps: a checkout, an onboarding flow, a multi-step form. Drive value from your own Back and Next buttons, and disable the steps that aren't reachable yet. For switching between views in any order, use Tabs; for how much of one task is done, use Progress.
**Built on:** Radix Slot.
**npm packages (installed by the CLI):** motion@^14.0.0, radix-ui@^1.7.0.

## Examples

### Checkout

Next fills the line to the next step, which takes the ring as the fill arrives, while the step you leave swaps its number for a check. Back plays it backwards. Press a step you've reached to jump back: each line empties in turn.

```tsx
"use client";

import { Button } from "@/components/ui/button";
import {
  Stepper,
  StepperIndicator,
  StepperItem,
  StepperSeparator,
  StepperTitle,
  StepperTrigger,
} from "@/components/ui/stepper";
import { useRef, useState } from "react";

const steps = ["Cart", "Shipping", "Payment", "Review"];

/*
 * A four-step checkout. Next and Back move one step: the line fills or empties, and the step you leave gets its
 * check (or loses it). Steps you've reached can be pressed to jump back; the ones ahead aren't reachable yet.
 * Past Review every step is done. When Back or Next can't go further, focus moves to the other one.
 */
export default function StepperCheckout() {
  const [step, setStep] = useState(2);
  const back = useRef<HTMLButtonElement>(null);
  const next = useRef<HTMLButtonElement>(null);
  const last = steps.length + 1;

  const go = (to: number) => {
    setStep(to);
    if (to === 1) next.current?.focus();
    if (to === last) back.current?.focus();
  };

  return (
    <div className="flex w-full max-w-xl flex-col gap-10">
      <Stepper value={step} onValueChange={setStep} aria-label="Checkout">
        {steps.map((title, index) => (
          <StepperItem key={title} step={index + 1} disabled={index + 1 > step}>
            <StepperTrigger>
              <StepperIndicator />
              <StepperTitle>{title}</StepperTitle>
            </StepperTrigger>
            <StepperSeparator />
          </StepperItem>
        ))}
      </Stepper>
      <div className="flex justify-end gap-2">
        <Button ref={back} variant="outline" size="sm" disabled={step === 1} onClick={() => go(step - 1)}>
          Back
        </Button>
        <Button ref={next} size="sm" disabled={step === last} onClick={() => go(step + 1)}>
          Next
        </Button>
      </div>
    </div>
  );
}
```

### Vertical

orientation="vertical", with a description under each title. Every step can be pressed here.

```tsx
import {
  Stepper,
  StepperDescription,
  StepperIndicator,
  StepperItem,
  StepperSeparator,
  StepperTitle,
  StepperTrigger,
} from "@/components/ui/stepper";

const steps = [
  { title: "Create your account", description: "Your name and a work email." },
  { title: "Invite your team", description: "Add the people you work with." },
  { title: "Connect a project", description: "Pick a repository to start from." },
  { title: "Go live", description: "Publish when you're ready." },
];

/*
 * Down the side, with a line under each title. Press any step: the lines fill or empty one after another on the
 * way there.
 */
export default function StepperVertical() {
  return (
    <Stepper defaultValue={2} orientation="vertical" aria-label="Setup" className="w-full max-w-xs">
      {steps.map(({ title, description }, index) => (
        <StepperItem key={title} step={index + 1}>
          <StepperTrigger>
            <StepperIndicator />
            <StepperTitle>{title}</StepperTitle>
            <StepperDescription>{description}</StepperDescription>
          </StepperTrigger>
          <StepperSeparator />
        </StepperItem>
      ))}
    </Stepper>
  );
}
```

## Related

- [Progress](https://ui.fewtone.com/components/progress.md): An accessible React progress bar and ring for Next.js and Tailwind CSS that show how far along a task is, with an indeterminate state.
- [Tabs](https://ui.fewtone.com/components/tabs.md): Accessible React tabs for Next.js, with an underline or pill that slides to the active tab and panels that glide in, built on Radix Tabs.
- [Button](https://ui.fewtone.com/components/button.md): An accessible React button for Next.js and Tailwind CSS with six variants, three sizes, icons and a soft tint on hover and press, built on a native button.
