Stepper

Show where a person is in a multi-step flow and what is done.

motionproduct
Preview
Stepper preview

When to use

  • Showing position in a strict multi-step flow like checkout or account setup.
  • Flows where people can jump back to completed steps, via onStepSelect.
  • Vertical timelines of steps with descriptions and error states.

When not to use

  • Use multi-step-form when you also want the step content, navigation, and success state.
  • Use onboarding-checklist for loosely ordered tasks.
  • Use progress when a single percentage is enough.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stepper",
  "type": "registry:ui",
  "title": "Stepper",
  "description": "Show where a person is in a multi-step flow and what is done.",
  "categories": [
    "feedback"
  ],
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/stepper/stepper.tsx",
      "type": "registry:component",
      "target": "@components/manicat/stepper/stepper.tsx"
    },
    {
      "path": "registry/components/stepper/stepper.module.css",
      "type": "registry:component",
      "target": "@components/manicat/stepper/stepper.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/stepper",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/stepper",
    "markdown": "https://uiarc.dev/components/stepper/markdown",
    "tags": [
      "motion",
      "product"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { useState } from "react";
import { Stepper } from "@/components/manicat/stepper/stepper";
import { Button } from "@/components/manicat/button/button";

const steps = [
  { id: "plan", label: "Plan", description: "Choose a template and a plan." },
  { id: "connect", label: "Connect", description: "Link your GitHub repository." },
  { id: "deploy", label: "Deploy", description: "Ship the first version." },
];

export function StepperExample() {
  const [current, setCurrent] = useState(1);

  return (
    <div className="grid w-full max-w-2xl gap-4">
      <Stepper steps={steps} current={current} onStepSelect={setCurrent} details="all" />
      <div className="flex gap-2">
        <Button size="sm" variant="secondary" onClick={() => setCurrent((value) => Math.max(0, value - 1))}>
          Back
        </Button>
        <Button size="sm" onClick={() => setCurrent((value) => Math.min(steps.length, value + 1))}>
          Next
        </Button>
      </div>
    </div>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Onboarding flow A step indicator driven by Back and Next, with completed steps clickable.

Onboarding flow A step indicator driven by Back and Next, with completed steps clickable. preview

Keyboard interactions

KeysAction
ArrowLeft / ArrowRight / ArrowUp / ArrowDownWith onStepSelect, moves focus between reachable steps (RTL aware).
Home / EndJumps to the first or the current step.
Enter / SpaceSelects a completed step.

Accessibility

  • Renders a labelled nav when interactive, otherwise role="group"; the current step has aria-current="step".
  • Each step appends screen-reader-only status text: Completed, Not started, or Error.
  • Step changes are announced in a polite live region as "Step 2 of 4: Shipping".
  • Upcoming steps are aria-disabled and removed from the tab order.

Motion

  • Connectors fill one after another when progress jumps several steps; the ring then grows around the new current marker.
  • Numbers morph into drawn checks or alerts; descriptions rise in while their slot springs to the new height.
  • Reduced motion applies all changes instantly.

Responsive behavior

  • Horizontal steppers switch to markers only with a caption below a 30rem container width.
  • Set orientation to vertical for sidebars or narrow columns where labels and descriptions should stay visible.
  • Labels and descriptions wrap with overflow-wrap, so long words do not overflow.

Performance

  • The stepper only indicates; it renders markers and text, with a ResizeObserver for the description slot height.

Notes for AI

  • Use to show position in a strict multi-step flow such as checkout or setup. Use onboarding-checklist for loosely ordered tasks.
  • The stepper only indicates; render the step content yourself and drive current. Set current to steps.length when done.