Components
Step Indicator
A vertical step indicator that shows progress through a multi-step flow. The rail is an 18px-wide capsule that fills from the top down to the last non-pending step, with rounded caps at both ends and at every filled→unfilled transition. Each row shows a status-aware right-side indicator: success check, progress ring, or empty circle.
Installation
bunx @happlyui/cli@latest add step-indicator
Dependencies
npm packages
@remixicon/react
Registry dependencies
These are automatically installed when you add this component.
happly-ui-utilsprogress-circle
Usage
import * as StepIndicator from "@/components/ui/step-indicator"
import { RiUser3Fill, RiMoneyDollarCircleFill } from "@remixicon/react"
<StepIndicator.Root>
<StepIndicator.Item
status="completed"
icon={RiUser3Fill}
title="Capability & Fit"
description="3 Questions"
/>
<StepIndicator.Item
status="active"
progress={50}
icon={RiMoneyDollarCircleFill}
title="Offer Details"
description="3 Questions"
/>
</StepIndicator.Root>
Examples
First Step Active
The flow has just started — only the first step is active, the rest are pending. The rail shows a small filled cap at the top with rounded ends.
Capability & Fit
3 Questions
Offer Details
3 Questions
Financing & Readiness
4 Questions
Supporting Documents
2 Questions
<StepIndicator.Composed
items={[
{ status: 'active', progress: 30, icon: RiUser3Fill, title: 'Capability & Fit', description: '3 Questions' },
{ status: 'pending', icon: RiMoneyDollarCircleFill, title: 'Offer Details', description: '3 Questions' },
{ status: 'pending', icon: RiQuestionFill, title: 'Financing & Readiness', description: '4 Questions' },
{ status: 'pending', icon: RiFileFill, title: 'Supporting Documents', description: '2 Questions' },
]}
/>
Mid Progress
First step completed, second step active. The filled rail extends from the top through the active step and ends with a rounded cap; the gray track resumes below with a rounded top.
Capability & Fit
3 Questions
Offer Details
3 Questions
Financing & Readiness
4 Questions
Supporting Documents
2 Questions
<StepIndicator.Composed
items={[
{ status: 'completed', icon: RiUser3Fill, title: 'Capability & Fit', description: '3 Questions' },
{ status: 'active', progress: 50, icon: RiMoneyDollarCircleFill, title: 'Offer Details', description: '3 Questions' },
{ status: 'pending', icon: RiQuestionFill, title: 'Financing & Readiness', description: '4 Questions' },
{ status: 'pending', icon: RiFileFill, title: 'Supporting Documents', description: '2 Questions' },
]}
/>
Last Step Active
Most steps completed, the final step is active. The rail extends through every position and the last step shows a progress ring on the right.
Capability & Fit
3 Questions
Offer Details
3 Questions
Financing & Readiness
4 Questions
Supporting Documents
2 Questions
<StepIndicator.Composed
items={[
{ status: 'completed', icon: RiUser3Fill, title: 'Capability & Fit', description: '3 Questions' },
{ status: 'completed', icon: RiMoneyDollarCircleFill, title: 'Offer Details', description: '3 Questions' },
{ status: 'completed', icon: RiQuestionFill, title: 'Financing & Readiness', description: '4 Questions' },
{ status: 'active', progress: 70, icon: RiFileFill, title: 'Supporting Documents', description: '2 Questions' },
]}
/>
All Completed
Every step is done — the rail is fully filled and every right-side adornment shows the success check.
Capability & Fit
3 Questions
Offer Details
3 Questions
Financing & Readiness
4 Questions
Supporting Documents
2 Questions
<StepIndicator.Composed
items={[
{ status: 'completed', icon: RiUser3Fill, title: 'Capability & Fit', description: '3 Questions' },
{ status: 'completed', icon: RiMoneyDollarCircleFill, title: 'Offer Details', description: '3 Questions' },
{ status: 'completed', icon: RiQuestionFill, title: 'Financing & Readiness', description: '4 Questions' },
{ status: 'completed', icon: RiFileFill, title: 'Supporting Documents', description: '2 Questions' },
]}
/>
Compound API
Use Root + Item directly for full control over each row (e.g., individual click handlers, per-row classes).
Capability & Fit
3 Questions
Offer Details
3 Questions
Financing & Readiness
4 Questions
Supporting Documents
2 Questions
<StepIndicator.Root>
<StepIndicator.Item status="completed" icon={RiUser3Fill} title="Capability & Fit" description="3 Questions" />
<StepIndicator.Item status="active" progress={50} icon={RiMoneyDollarCircleFill} title="Offer Details" description="3 Questions" />
<StepIndicator.Item status="pending" icon={RiQuestionFill} title="Financing & Readiness" description="4 Questions" />
<StepIndicator.Item status="pending" icon={RiFileFill} title="Supporting Documents" description="2 Questions" />
</StepIndicator.Root>
Custom Rail Colors
Override the filled and unfilled rail Tailwind classes via railFilledClassName and railTrackClassName to retheme the indicator.
Capability & Fit
3 Questions
Offer Details
3 Questions
Financing & Readiness
4 Questions
Supporting Documents
2 Questions
<StepIndicator.Composed
railFilledClassName="bg-information-base"
railTrackClassName="bg-bg-weak-50"
items={items}
/>
API Reference
StepIndicator.Root
Container that computes rail-fill state from its Item children and threads it down via cloneElement. Forwards a ref to the underlying div and accepts standard div props.
| Prop | Type | Default | Description |
|---|---|---|---|
railFilledClassName | string | 'bg-primary-base' | Tailwind class for the filled rail and the icon bulge of non-pending steps. Override to retheme. |
railTrackClassName | string | 'bg-bg-soft-200' | Tailwind class for the unfilled rail track and pending icon bulges. |
className | string | - | Additional class names. Default is `flex w-full flex-col` (no gap — gaps are inside each Item so the rail reads as one continuous capsule). |
StepIndicator.Item
A single row in the indicator. Reads its position from Root via cloneElement-injected props to render the correct rail-fill state. Must be a direct child of Root (or rendered via Composed).
| Prop | Type | Default | Description |
|---|---|---|---|
status | 'pending' | 'active' | 'completed' | - | Drives the rail bulge color, the right-side adornment, and the rail-fill computation in Root. |
icon | React.ElementType | - | Icon component (e.g. from @remixicon/react) rendered inside the rail bulge at 12px. Required. |
title | ReactNode | - | Primary label shown in the content column. |
description | ReactNode | - | Secondary line under the title (e.g. '3 Questions', a date, or a hint). |
progress | number | 50 | Progress 0–100 used by the right-side ProgressCircle when status is 'active'. Ignored otherwise. |
StepIndicator.Composed
Data-driven shorthand that renders Root + Item from an items array. Accepts all Root props plus an `items` array.
| Prop | Type | Default | Description |
|---|---|---|---|
items | { status: 'pending' | 'active' | 'completed'; icon: React.ElementType; title: ReactNode; description?: ReactNode; progress?: number; onClick?: (e: MouseEvent) => void }[] | - | Array of step definitions, rendered in order. |