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 (olelement).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 (lielement).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__stepand.stepper__indicator[data-clickable="true"]- Marks an interactive step button[data-complete]- Set on a fully filled separator track
CSS Variables
| Variable | Default | Description |
|---|---|---|
--stepper-indicator-size | 28px (md) | Size of the indicator circle |
--stepper-separator-size | 2px | Thickness of the separator line |
--stepper-vertical-gap | 16px (md) | Gap between vertical steps |
--stepper-active-color | var(--accent) | Color of the active step |
--stepper-complete-color | var(--accent) | Color of completed steps |
--stepper-complete-fg | var(--accent-foreground) | Foreground color of the completed indicator |
--stepper-inactive-border | var(--border) | Border color of the inactive indicator |
--stepper-inactive-fg | var(--muted) | Text color of the inactive indicator |
--stepper-separator-progress | 0 | Progress 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.
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Layout direction |
size | "sm" | "md" | "lg" | "md" | Size variant |
currentStep | number | - | The current active step index (controlled) |
defaultStep | number | 0 | The initial step index (uncontrolled) |
onStepChange | (step: number) => void | - | Called when a step is clicked; makes steps interactive when provided |
animateOnMount | boolean | false | Play a subtle staggered entrance animation when the stepper first mounts |
className | string | - | 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.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | ((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 |
className | string | - | 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.
| Prop | Type | Default | Description |
|---|---|---|---|
progress | number | - | Explicit progress value (0–1). Auto-computed from the step status when omitted |
force | boolean | false | Force rendering even on the last step |
useStepperStep
Hook to access the per-step context from any descendant of Stepper.Step.
| Property | Type | Description |
|---|---|---|
index | number | Zero-based step index |
status | "inactive" | "active" | "complete" | Current step status |
isLast | boolean | Whether this is the last step |





