Equality
Equality

Progress Indicator

Communicates a user's progress through a sequence of steps

View 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:

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

Basic usage with required properties:

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

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

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

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

<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 colourediting, empty, neutral, success, info, dangerneutral
hrefRenders the step as an <a>string
onClickRenders the step as a <button>(e: MouseEvent) => void