HapplyUI

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-utils
  • progress-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.

PropTypeDefaultDescription
railFilledClassNamestring'bg-primary-base'Tailwind class for the filled rail and the icon bulge of non-pending steps. Override to retheme.
railTrackClassNamestring'bg-bg-soft-200'Tailwind class for the unfilled rail track and pending icon bulges.
classNamestring-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).

PropTypeDefaultDescription
status'pending' | 'active' | 'completed'-Drives the rail bulge color, the right-side adornment, and the rail-fill computation in Root.
iconReact.ElementType-Icon component (e.g. from @remixicon/react) rendered inside the rail bulge at 12px. Required.
titleReactNode-Primary label shown in the content column.
descriptionReactNode-Secondary line under the title (e.g. '3 Questions', a date, or a hint).
progressnumber50Progress 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.

PropTypeDefaultDescription
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.

Previous
Pagination