v1.0

Stepper

Compound component that tracks progress through an ordered sequence of steps, with a status per step.

  1. 1.Create your accountCompleted
  2. 2.Verify your emailCompleted
  3. 3.Set up your workspace
  4. 4.Invite your team
Pro
  1. Completed
    Create your account
  2. 2
    Set up your workspace
  3. 3
    Invite your team

Description

Stepper is a compound component that renders an ordered list (<ol>) of steps and marks each one as completed, active, error, or locked. The root hands orientation, size, and layout down through context, so the sub-parts style themselves from the step's status without per-element wiring.

Reach for it in multi-step flows where the user needs to see where they are and what is left: onboarding, checkout, account setup wizards, and long forms split into stages. It works vertically or horizontally, and ships a dots progress indicator and a status-tinted badge layout for tighter surfaces.

This component is tiered. The free tier ships the dots progress (StepperDots) and the status-badge steps (StepperBadgeItem). The signature numbered-icon layout with connector lines, per-step content, descriptions, actions, and the compact layout is Pro: run add stepper with a seat to swap in the richer overlay (same API, extra exports). If the flow only swaps a panel in place, use Tabs. For an indeterminate "working" state with no discrete steps, use Progress or Spinner. For hierarchical path navigation, use Breadcrumb.

Installation

pnpm dlx @create-ui/cli add stepper

Anatomy

Stepper provides a context (orientation, size, layout) that every sub-part reads. Each StepperItem owns a status and passes it to the icon, line, and text inside it.

<Stepper>
  <StepperItem status="...">
    <StepperIndicator>
      <StepperIcon />
      <StepperLine />
    </StepperIndicator>
    <StepperContent>
      <StepperContentHead>
        <StepperTitle />
        <StepperDescription />
      </StepperContentHead>
      <StepperActions />
    </StepperContent>
  </StepperItem>
</Stepper>

The free tier composes two shorthands instead of the full item tree: StepperDots for a dot progress row, and StepperBadgeItem for status-tinted step bars (<Stepper layout="badge">).

Usage

import { Stepper, StepperBadgeItem } from "@/components/ui/stepper"
<Stepper layout="badge">
  <StepperBadgeItem status="active" number="1." title="Set up your workspace" />
</Stepper>

Examples

The free tier covers the two examples below (Dots and Sizes); the rest render the Pro overlay and are marked with a Pro badge.

Dots

StepperDots renders a compact progress row. Set count and defaultActiveIndex (or a controlled activeIndex), and pick a shape: circle, pill (the active dot stretches), or bar.

Sizes

size on the root scales the whole stepper. The free badge layout at sm and md: padding, type, and icon size all move together.

  1. 1.AccountCompleted
  2. 2.Workspace
  3. 3.Team
  1. 1.AccountCompleted
  2. 2.Workspace
  3. 3.Team

Horizontal

Set orientation="horizontal" on the root to lay steps left to right, with the connector line running between each StepperIcon.

Pro
  1. Completed
    Account
  2. 2
    Workspace
  3. 3
    Team

Compact

StepperCompactItem (inside <Stepper layout="compact">) is a condensed step: an icon plus a short label. Use alignment (top, left, right) to place the label relative to the icon.

Pro
  1. 1
    Step 1

    Account

  2. 2
    Step 2

    Workspace

  3. 3
    Step 3

    Team

  1. 1Account
  2. 2Workspace
  3. 3Team

Content and actions

Each step can carry a StepperTitle, a StepperDescription, and a StepperActions row (usually Buttons on the active step) inside StepperContent.

Pro
  1. Completed
    Create your account

    Your account is ready to go.

  2. 2
    Set up your workspace

    Name your workspace and choose a URL.

  3. 3
    Invite your team

    Add teammates so they can collaborate.

Step icons

StepperIcon is the step marker. variant sets the color, appearance picks the fill (soft, outline, solid), and an empty success or error icon auto-renders a check or warning glyph.

Pro
123CompletedError

Accessibility

The root is an ordered list (<ol>), so steps are announced in order. The active step (and its StepperTrigger) sets aria-current="step". Interactive steps use a real StepperTrigger (<button>); static steps are not focusable.

KeyDescription
TabMoves focus to the next step trigger or interactive dot.
Space EnterActivates the focused step trigger or dot.

ARIA notes:

  • The root sets aria-label="Progress" by default. Pass your own aria-label or aria-labelledby when the surrounding context already names the flow.
  • The active item and StepperTrigger set aria-current="step"; completed and error icons add an sr-only "Completed" / "Error" label so state is not conveyed by color alone.
  • StepperDots with interactive (the default) is a role="group" of per-dot <button>s, each with its own aria-label and aria-current. With interactive={false} it becomes a role="progressbar" and sets aria-valuemin, aria-valuemax, aria-valuenow, and aria-valuetext.
  • StepperLine is decorative (role="presentation", aria-hidden); it carries no meaning for assistive tech.
  • Disabled steps skip their click handler and set aria-disabled.

Styling

Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):

<Stepper className="w-[320px]">
  <StepperItem status="active" className="gap-4" />
</Stepper>

Data slots and attributes: the component sets these for CSS targeting.

  • data-slot="stepper" on the root <ol>.
  • data-slot="stepper-item" on each step.
  • data-slot="stepper-trigger" on the interactive step button.
  • data-slot="stepper-indicator" on the icon + line column.
  • data-slot="stepper-icon" on the step marker.
  • data-slot="stepper-line" on the connector, with data-slot="stepper-line-fill" on its animated fill.
  • data-slot="stepper-dot" on a single dot, data-slot="stepper-dots" on the dots row.
  • data-slot="stepper-content", data-slot="stepper-content-head", data-slot="stepper-heading" on the text column wrappers.
  • data-slot="stepper-title", data-slot="stepper-description", data-slot="stepper-actions" on the text and actions.
  • data-status="active" | "completed" | "error" | "locked", data-orientation, data-size, and data-layout on the root, items, and text.
  • data-variant, data-appearance, data-shape, data-active, data-highlighted, and data-disabled on the icon, dot, and line.

Target a step's status in CSS:

[data-slot="stepper-item"][data-status="error"] {
  /* ... */
}
  • Tabs: use this when each option swaps a content panel within the same surface, not a linear flow.
  • Progress: use this for a single indeterminate or percentage bar with no discrete steps.
  • Breadcrumb: use this for hierarchical path navigation rather than sequential progress.
  • Pagination: use this for moving through pages of content.

API Reference

Stepper

Root ordered list that owns the orientation / size / layout context. Extends React.ComponentProps<"ol">, so standard list attributes (id, aria-label, aria-labelledby, etc.) are accepted.

Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical""vertical"Lays steps in a column or a row.
size"sm" | "md""md"Size scale shared by every sub-part via context.
layout"default" | "compact" | "badge""default"Selects the step layout; pairs with StepperCompactItem / StepperBadgeItem.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-StepperItem, StepperBadgeItem, or StepperCompactItem children.

StepperItem

One step in the full (Pro) layout. Extends React.ComponentProps<"li"> and provides the per-step status context.

Props

PropTypeDefaultDescription
status"active" | "completed" | "error" | "locked""locked"Step status; drives icon, line, and text color.
disabledboolean-Dims the step and disables its trigger (ignored when active).
layout"default" | "compact" | "badge"root valueOverrides the root layout for this step.
variant"primary" | "info" | "success" | "error" | "neutral-light" | "neutral-solid"-Forces a color scheme for the step's icon and connector line. (advanced)
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-StepperIndicator and StepperContent.

StepperTrigger

Interactive step target. Extends React.ComponentProps<"button">; renders a <button> by default, or any element via asChild (Radix Slot).

Props

PropTypeDefaultDescription
asChildbooleanfalseRender as the child element via Radix Slot.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Trigger content (usually a StepperTitle).

StepperIndicator

Column that holds the step's icon and its trailing connector line. Extends React.ComponentProps<"div">.

Props

PropTypeDefaultDescription
lineReact.ReactNode<StepperLine />Overrides the trailing connector (e.g. an animated fill line).
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Usually a StepperIcon.

StepperIcon

Step marker rendered as a <span>. Extends React.ComponentProps<"span">. An empty success or error icon auto-renders a check or warning glyph.

Props

PropTypeDefaultDescription
variant"primary" | "info" | "success" | "error" | "neutral-light" | "neutral-solid"derived from statusColor scheme of the marker.
appearance"soft" | "outline" | "solid""solid"Fill treatment.
shape"rounded" | "pill"pill inside an itemCorner shape of the marker.
size"sm" | "md"root valueMarker size.
step"main" | "sub""main"sub renders the smaller sub-step marker.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Step number or a custom icon.

StepperDot

A single dot. Extends React.ComponentProps<"span">. Used by StepperDots, or on its own.

Props

PropTypeDefaultDescription
variant"neutral" | "primary" | "inverse""neutral"Dot color scheme.
appearance"solid" | "outline""solid"Filled or outlined.
shape"circle" | "pill" | "bar""circle"Dot shape.
size"xs" | "sm" | "md"root valueDot size.
activeboolean-Marks the dot as the current step.
highlightedbooleanfalseAdds an outline ring when active.

StepperDots

Dot progress row. Extends React.ComponentProps<"div">. Interactive by default (each dot is a button); pass interactive={false} for a read-only progress bar.

Props

PropTypeDefaultDescription
countnumber-Number of dots to render.
activeIndexnumber-Controlled active index.
defaultActiveIndexnumber0Uncontrolled initial active index.
onActiveIndexChange(index: number) => void-Fires when a dot is clicked (interactive mode).
interactivebooleantrueRenders clickable dots (role="group") vs a role="progressbar".
shape"circle" | "pill" | "bar""circle"Dot shape; pill stretches only the active dot.
variant"neutral" | "primary" | "inverse""primary"Dot color scheme.
appearance"solid" | "outline""solid"Filled or outlined dots.
highlightedbooleanfalseAdds a ring around the active dot.
size"xs" | "sm" | "md"root valueDot size.
labelstring"Progress"Accessible label for the row.
classNamestring-Tailwind classes merged via cn().

StepperLine

Connector line between steps, rendered as a decorative <span> (role="presentation"). Extends React.ComponentProps<"span">. Pass fill to animate a progress fill.

Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical"root valueLine direction.
variant"neutral-light" | "neutral-solid" | "primary" | "info" | "success" | "error"derived from statusLine color.
appearance"solid" | "soft"derived from statusLine weight.
size"sm" | "md"root valueLine thickness scale.
fillboolean-When set, animates a fill from empty to full. (advanced)
fillVariantStepperLineVariant"info"Color of the animated fill. (advanced)
durationnumber700Fill animation duration in ms. (advanced)
onFillEnd() => void-Fires when the fill animation finishes. (advanced)
classNamestring-Tailwind classes merged via cn().

StepperContent

Text column beside the indicator. Extends React.ComponentProps<"div">. Takes className and children (a StepperContentHead and optional StepperActions).

StepperContentHead

Wrapper for the title and description. Extends React.ComponentProps<"div">. Takes className and children.

StepperHeading

Row that lays out a title next to trailing content (e.g. a badge). Extends React.ComponentProps<"div">. Takes className and children.

StepperTitle

Step title rendered as a <span>. Extends React.ComponentProps<"span">.

Props

PropTypeDefaultDescription
status"active" | "completed" | "error" | "locked"item valueOverrides the status-derived color.
size"sm" | "md"root valueTitle size.
tone"default" | "accent" | "inherit"layout valueColor tone; accent follows the status, inherit uses the parent color.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Title text.

StepperDescription

Secondary line under the title, rendered as a <p>. Extends React.ComponentProps<"p">.

Props

PropTypeDefaultDescription
status"active" | "completed" | "error" | "locked"item valueOverrides the status-derived color.
size"sm" | "md"root valueDescription size.
tone"default" | "accent" | "inherit"layout valueColor tone.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Description text.

StepperActions

Row for step buttons. Extends React.ComponentProps<"div">. Takes className and children (usually Buttons).

StepperCompactItem

Condensed step (icon + label) for the compact layout. Extends Omit<React.ComponentProps<"li">, "onClick">.

Props

PropTypeDefaultDescription
status"active" | "completed" | "error" | "locked""locked"Step status.
alignment"top" | "left" | "right""top"Label position relative to the icon.
size"sm" | "md"root valueStep size.
indicatorReact.ReactNode-Content of the step icon (a number or glyph).
stepReact.ReactNode-Small "Step N" label (top alignment).
titleReact.ReactNode-Step label.
disabledboolean-Dims the step and skips its click handler.
showLinebooleantrueRenders the trailing connector line.
lineReact.ReactNode-Overrides the connector line.
onClickReact.MouseEventHandler<HTMLButtonElement>-Makes the step interactive.
classNamestring-Tailwind classes merged via cn().

StepperBadgeItem

Status-tinted step bar (free layout). Extends Omit<React.ComponentProps<"li">, "onClick">.

Props

PropTypeDefaultDescription
status"active" | "completed" | "error" | "locked""locked"Step status; drives the bar tint.
size"sm" | "md"root valueStep size.
leadIconReact.ReactNode-Icon rendered before the number.
numberReact.ReactNode-Step number (e.g. "1.").
titleReact.ReactNode-Step label.
statusIconReact.ReactNode-Overrides the auto status glyph.
showStatusIconbooleantrueRenders the trailing status glyph.
disabledboolean-Dims the step and skips its click handler.
onClickReact.MouseEventHandler<HTMLButtonElement>-Makes the step interactive.
classNamestring-Tailwind classes merged via cn().