EQTY Lab Equality

Progress Indicator

Communicates a user's progress through a sequence of steps

View as Markdown

Overview

The Progress Indicator communicates a user’s position within a multi-step process such as policy or indicator creation. It renders a sequence of steps along a track, with the current step highlighted and each step’s state conveyed through a status icon.

It is composed of two components: ProgressIndicator (the parent that draws the track and arranges the steps) and ProgressIndicatorStep (each individual step). The parent takes a currentIndex and positions the track’s filled segment over that step; each step derives its own active state by comparing its index to it.

Progress Indicator should not be used with fewer than three steps.

Usage

Import the components:

ts
import { ProgressIndicator, ProgressIndicatorStep } from "@eqtylab/equality";

Basic usage with required properties:

tsx
<ProgressIndicator aria-label="Account setup progress" currentIndex={1}>
  <ProgressIndicatorStep name="Account" status="success" />
  <ProgressIndicatorStep name="Verification" status="editing" />
  <ProgressIndicatorStep name="Confirm" status="neutral" />
</ProgressIndicator>

Variants

Horizontal (default)

The default layout arranges steps in a row. The example below mixes every status so each icon is visible. The step at currentIndex (Verification) is marked with aria-current="step" and the track fills its segment.

tsx
<ProgressIndicator aria-label="Progress Indicator" currentIndex={2}>
  <ProgressIndicatorStep
    name="Success"
    description="Completed"
    status="success"
  />
  <ProgressIndicatorStep
    name="Danger"
    description="Action required"
    status="danger"
  />
  <ProgressIndicatorStep
    name="Editing"
    description="In progress"
    status="editing"
  />
  <ProgressIndicatorStep name="Info" description="Optional" status="info" />
  <ProgressIndicatorStep name="Neutral" status="neutral" />
  <ProgressIndicatorStep name="Empty" status="empty" />
</ProgressIndicator>

Vertical

Set layout="vertical" to stack the steps. The track and fill re-orient automatically.

tsx
<ProgressIndicator
  layout="vertical"
  currentIndex={2}
  aria-label="Progress Indicator"
>
  <ProgressIndicatorStep
    name="Success"
    description="Completed"
    status="success"
  />
  {/* …remaining steps… */}
</ProgressIndicator>

Interactive (onClick)

When a step is given an onClick handler it renders as a <button>, making it focusable and keyboard-operable.

tsx
const [active, setActive] = useState(1);

<ProgressIndicator aria-label="Policy creation steps" currentIndex={active}>
  {steps.map((name, index) => (
    <ProgressIndicatorStep
      key={name}
      name={name}
      status={
        index < active ? "success" : index === active ? "editing" : "neutral"
      }
      onClick={() => setActive(index)}
    />
  ))}
</ProgressIndicator>;

When a step is given an href it renders as an <a>.

tsx
<ProgressIndicator aria-label="Documentation progress" currentIndex={1}>
  <ProgressIndicatorStep
    name="Introduction"
    status="success"
    href="#introduction"
  />
  <ProgressIndicatorStep
    name="Installation"
    status="editing"
    href="#installation"
  />
  <ProgressIndicatorStep name="Usage" status="neutral" href="#usage" />
</ProgressIndicator>

If a step has neither href nor onClick, it renders as a non-interactive <div> that is not focusable.

Props

ProgressIndicator

NameDescriptionTypeDefaultRequired
layoutOrientation of the stepshorizontal, verticalhorizontal❌
currentIndexArray index of the current (active) stepnumber0✅
elevationElevation applied to each step’s marker iconsunken, base, raised, overlayraised❌
aria-labelAccessible label for the step liststring"Progress"❌
childrenOne or more ProgressIndicatorStep componentsReactNode—✅

ProgressIndicatorStep

NameDescriptionTypeDefaultRequired
nameThe step labelstring—✅
descriptionSecondary text shown beneath the namestring—❌
statusControls the step’s icon and colorediting, empty, neutral, success, info, dangerneutral❌
hrefRenders the step as an <a>string—❌
onClickRenders the step as a <button>(e: MouseEvent) => void—❌