27.7k

Stepper

A step-by-step progress indicator with numbered, icon, and bullet variants in horizontal or vertical layouts.

Import

import { Stepper } from '@darkcode-ui/react';

Usage

The currentStep (controlled) or defaultStep (uncontrolled) prop marks the active step. Every step before it is automatically rendered as complete.

import {Stepper} from "@darkcode-ui/react";

const steps = ["Account", "Profile", "Review"];

export function Basic() {

Anatomy

Import the Stepper component and access all parts using dot notation.

import { Stepper } from '@darkcode-ui/react';

export default () => (
  <Stepper>
    <Stepper.Step>
      <Stepper.Indicator>
        <Stepper.Icon /> {/* Optional, rendered inside the indicator */}
      </Stepper.Indicator>
      <Stepper.Content>
        <Stepper.Title />
        <Stepper.Description /> {/* Optional */}
      </Stepper.Content>
      <Stepper.Separator /> {/* Hidden on the last step */}
    </Stepper.Step>
  </Stepper>
)

With Icons

Return a <Stepper.Icon> from the <Stepper.Indicator> render function for inactive and active steps. Returning undefined for completed steps falls back to the default animated checkmark.

"use client";

import {Stepper} from "@darkcode-ui/react";
import {Icon} from "@iconify/react";

With Descriptions

Add a <Stepper.Description> next to the <Stepper.Title> inside <Stepper.Content>.

import {Stepper} from "@darkcode-ui/react";

const steps = [
  {description: "Enter your account details", title: "Account"},
  {description: "Set up your profile", title: "Profile"},

Sizes

Use the size prop to render sm, md (default), or lg steppers.

import {Stepper} from "@darkcode-ui/react";

const steps = ["Account", "Profile", "Review"];

export function Sizes() {

Bullet Steps

Pass empty children and a smaller size to <Stepper.Indicator> to render minimal bullet markers instead of numbers.

import {Stepper} from "@darkcode-ui/react";

const steps = ["Start", "Details", "Payment", "Done"];

export function BulletSteps() {

Vertical

Set orientation="vertical" to stack steps with a vertical connector.

import {Stepper} from "@darkcode-ui/react";

const steps = ["Account", "Profile", "Review"];

export function Vertical() {

Vertical Sizes

import {Stepper} from "@darkcode-ui/react";

const steps = ["Account", "Profile", "Review"];

export function VerticalSizes() {

Vertical With Icons

"use client";

import {Stepper} from "@darkcode-ui/react";
import {Icon} from "@iconify/react";

Controlled

Provide currentStep together with onStepChange to control the active step. Passing onStepChange also makes each step clickable.

"use client";

import {Button, Stepper} from "@darkcode-ui/react";
import React from "react";

Controlled Vertical

"use client";

import {Button, Stepper} from "@darkcode-ui/react";
import React from "react";

Custom Color

Override the --stepper-active-color, --stepper-complete-color, and --stepper-complete-fg CSS variables via the style prop to recolor the active and completed states.

import type {CSSProperties} from "react";

import {Stepper} from "@darkcode-ui/react";

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

Custom Color Vertical

import type {CSSProperties} from "react";

import {Stepper} from "@darkcode-ui/react";

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

Custom Completed Icon

Use the <Stepper.Indicator> render function to swap the default checkmark for your own icon on completed steps.

"use client";

import {Stepper} from "@darkcode-ui/react";
import {Icon} from "@iconify/react";

Display Only

Pass currentStep without onStepChange to render a non-interactive, read-only stepper.

import {Stepper} from "@darkcode-ui/react";

const steps = ["Account", "Profile", "Review"];

export function DisplayOnly() {

Dynamic Icon

Render a <Stepper.Icon> for every status, including completed steps.

import {Stepper} from "@darkcode-ui/react";
import {Icon} from "@iconify/react";

const steps = [
  {icon: "gravity-ui:box", title: "Order"},

Render Function

Map over your data to render steps declaratively — indexes and the last-step state are resolved automatically.

import {Stepper} from "@darkcode-ui/react";

const data = [
  {description: "Choose a plan", title: "Plan"},
  {description: "Add payment method", title: "Billing"},

Package Tracking

"use client";

import {Stepper} from "@darkcode-ui/react";
import {Icon} from "@iconify/react";

Free Trial Timeline

Pass an explicit progress value (0–1) to <Stepper.Separator> to render partially filled connectors.

import {Stepper} from "@darkcode-ui/react";

const events = [
  {description: "You started your 14-day free trial", title: "Trial started"},
  {description: "We'll email you a heads up", title: "Reminder in 11 days"},

Onboarding Timeline

"use client";

import {Stepper} from "@darkcode-ui/react";
import {Icon} from "@iconify/react";

Animated Entrance

By default the stepper renders settled and only animates on interaction (the active step pops with a soft ring and completed steps draw their checkmark when you move between steps). Set animateOnMount to play a subtle staggered entrance when the stepper first appears — ideal for landing and onboarding pages. All motion respects the user's reduced-motion preference.

"use client";

import {Button, Stepper} from "@darkcode-ui/react";
import React from "react";

Styling

CSS Classes

The Stepper component uses these CSS classes:

Base & Size Classes

  • .stepper - Base root container (ol element)
  • .stepper--sm - Small size (22px indicator)
  • .stepper--md - Medium size (28px indicator, default)
  • .stepper--lg - Large size (36px indicator)

Orientation Classes

  • .stepper--horizontal - Horizontal layout (default)
  • .stepper--vertical - Vertical layout

Element Classes

  • .stepper__step - Individual step wrapper (li element)
  • .stepper__step-button - Interactive button (or static wrapper) inside each step
  • .stepper__indicator - Circle badge showing the step number, icon, or checkmark
  • .stepper__icon - Icon wrapper inside the indicator
  • .stepper__content - Wrapper for the title and description
  • .stepper__title - Step title text
  • .stepper__description - Step description text
  • .stepper__separator - Connector line container between steps
  • .stepper__separator-track - Background rail of the separator
  • .stepper__separator-fill - Colored progress overlay inside the track

Data Attributes

  • [data-status="inactive" | "active" | "complete"] - Step status, set on .stepper__step and .stepper__indicator
  • [data-clickable="true"] - Marks an interactive step button
  • [data-complete] - Set on a fully filled separator track

CSS Variables

VariableDefaultDescription
--stepper-indicator-size28px (md)Size of the indicator circle
--stepper-separator-size2pxThickness of the separator line
--stepper-vertical-gap16px (md)Gap between vertical steps
--stepper-active-colorvar(--accent)Color of the active step
--stepper-complete-colorvar(--accent)Color of completed steps
--stepper-complete-fgvar(--accent-foreground)Foreground color of the completed indicator
--stepper-inactive-bordervar(--border)Border color of the inactive indicator
--stepper-inactive-fgvar(--muted)Text color of the inactive indicator
--stepper-separator-progress0Progress value (0–1) controlling the separator fill

API Reference

Stepper

The root component. Renders an ol element and tracks step progress. Also supports all native ol HTML attributes.

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Layout direction
size"sm" | "md" | "lg""md"Size variant
currentStepnumber-The current active step index (controlled)
defaultStepnumber0The initial step index (uncontrolled)
onStepChange(step: number) => void-Called when a step is clicked; makes steps interactive when provided
animateOnMountbooleanfalsePlay a subtle staggered entrance animation when the stepper first mounts
classNamestring-Additional CSS classes

Stepper.Step

A single step wrapper. Renders an li element and provides step context to its children. Also supports all native li HTML attributes.

Stepper.Indicator

The circle badge showing the step number, icon, or checkmark. Defaults to the step number for inactive/active steps and an animated checkmark for completed steps.

PropTypeDefaultDescription
childrenReactNode | ((state: { index: number; status: StepperStatus; isLast: boolean }) => ReactNode)-Custom content overriding the default number/checkmark. Returning nullish from the render function falls back to the default
classNamestring-Additional CSS classes

Stepper.Content

Flex wrapper for the title and description. Renders a span and supports all native span HTML attributes.

Stepper.Title

Step title text. Renders a span and supports all native span HTML attributes.

Stepper.Description

Step description text. Renders a span and supports all native span HTML attributes.

Stepper.Icon

Icon wrapper rendered inside the indicator. Renders a span and supports all native span HTML attributes.

Stepper.Separator

Connector line between steps. Automatically hidden on the last step. Renders a div and supports all native div HTML attributes.

PropTypeDefaultDescription
progressnumber-Explicit progress value (0–1). Auto-computed from the step status when omitted
forcebooleanfalseForce rendering even on the last step

useStepperStep

Hook to access the per-step context from any descendant of Stepper.Step.

PropertyTypeDescription
indexnumberZero-based step index
status"inactive" | "active" | "complete"Current step status
isLastbooleanWhether this is the last step

On this page