Communicates progress through the ordered steps of a wizard or multi-step flow.

Importing

import { Stepper, StepperStep } from '@customerio/pluma-components/react';

Usage

Use Stepper as the ordered container and compose one Step per stage of the flow. Each step takes a label, a status (incomplete, complete, critical, or caution), isCurrent for the stage the customer is on, and isDisabled for gated steps. The Stepper numbers the steps automatically and fills the connecting line green between adjacent completed steps, so the indicator always reflects real progress.

Loading editor

Steps usually represent real destinations in a flow. Give a Step an href to render it as a link (through PlainButton, so it uses the app's router and correctly de-activates when the step is disabled), or an onClick to render it as a button. Disabled steps drop their href and ignore clicks automatically, so future, not-yet-enabled steps can't be navigated to.

Loading editor

Content

content controls what each marker shows. The default, number, prints the step's position. icon shows a per-step icon instead (completed steps still show a check). minimal renders bare dots with no numbers or labels — the lightest treatment, for read-only or quick click-through flows. Even in minimal, keep setting label: it stays available to assistive technology as the step's name.

minimal markers stay bare whatever the step's status: the completed step's check and both attention icons are dropped along with the numbers, leaving the coin's color as the only visual difference between states. Don't use minimal for a flow where a step's status carries weight — number or icon keeps the glyphs. The status is still announced either way, since that text lives on the step's control rather than in the marker.

Loading editor

Minimal

Loading editor

Size

size sets the marker (coin) size for the whole Stepper — Coin's size scale: sm, md (default), lg, or xl. The connector thickness stays constant.

Loading editor

Layout

By default (layout="fill") the stepper spans the full width of its container, spreading the steps evenly. Use layout="fit" for a compact stepper that hugs its content with a consistent step width and centers itself — useful when the stepper should sit centered in a wider container rather than stretch across it.

Loading editor

Orientation

By default (orientation="horizontal") steps run in a row with the label beneath each marker. Use orientation="vertical" to stack them in a column with the label beside each marker — for a sidebar guide or a long form chunked into stages. All states, colors, and the fill-up-to-current behavior are identical; only the axis changes. (layout only applies to the horizontal orientation.)

Loading editor

Attention statuses

Two of the four status values flag a step that needs going back to. critical is for a step whose errors block finishing the flow — the customer cannot submit until they are fixed. caution is for a step that wants a look but doesn't block — an unusual value, a default they may not have meant to keep, a warning from validation that isn't fatal.

The rule for choosing between them is whether the flow can still be completed: red blocks, yellow doesn't. It is the same red-versus-yellow split Pluma uses everywhere else — critical for the invalid field that stops a form being submitted, caution for the advisory that doesn't.

Each marker turns its semantic color and shows the icon that semantic carries elsewhere in Pluma (error, the circled exclamation, for critical; warning, the triangle, for caution), so the two are told apart by shape as well as hue. Each also carries visually-hidden text — "has errors" and "needs attention" — so the status is never conveyed by color alone.

These markers are a pointer, not the message. They tell someone which step to go back to; they never say what is wrong. Keep the inline field errors on the step itself, and any summary on a review step, exactly as they are — a marker complements them and must not replace them.

Loading editor

Give attention steps an href (or onClick) wherever the flow allows it: the point of flagging a step is that someone can get back to it.

A step can be both the one they are on and the one with the problem — coming back to fix an errored step is the ordinary case. isCurrent behaves exactly as it always does, including aria-current="step"; on the marker the status wins, keeping its red or yellow coin with the current step's accent ring drawn around it.

Loading editor

An attention step is not a completed one, so the connecting lines around it stay grey — the green run keeps meaning "this stretch is done".

States

Set status="complete" on finished steps — their marker shows a check, and the line between two adjacent completed steps turns green. Mark the stage the customer is on with isCurrent; it bolds the label and draws an accent-colored ring around the marker (keeping its neutral surface), but it doesn't color any line, so a stepper someone has jumped ahead in keeps its lines grey until the earlier steps are actually done. A step that is both complete and current keeps its solid green check marker and gains that same ring. Use isDisabled for steps that can't be reached yet because an earlier step isn't done. For the two attention statuses, see Attention statuses above.

API

Default:'number'

What each step's marker shows: the auto-numbered position (number), a per-step icon, or a bare dot with no number or label (minimal). Applies to every step.

Default:'fill'

How steps are distributed horizontally. fill (default) spreads them across the full width; fit makes the stepper hug its content and center itself, with a consistent step width — for a compact stepper centered in a wider container. Only affects the horizontal orientation.

Default:'horizontal'

Which way the steps run. horizontal (default) lays them out in a row with the label beneath each marker; vertical stacks them in a column with the label beside each marker — for a sidebar guide or a long, chunked form.

Default:'md'

Marker (coin) size for every step.

Makes the step a link to the route it represents. Rendered through PlainButton, so it uses the app's link component and is correctly inert when the step is disabled (the href is dropped and clicks are blocked).

Icon shown in the marker when the Stepper's content is icon. Completed steps show a check instead, regardless of this.

Default:false

Marks this step as the one the customer is currently on — bolds the label, fills the marker with the active treatment, and sets aria-current="step".

Default:false

Gates the step (usually because an earlier step isn't done): mutes it and makes it inert.

The step's label, shown beneath the marker. In minimal steppers it isn't rendered visibly but is still used as the step's accessible name.

Click handler for the step. With no href, the step renders as a button; with an href, it fires on activation alongside navigation. Not called when the step is disabled.

Default:'incomplete'

The step's state: whether it's been completed (complete), or needs attention — critical for a step whose errors block finishing the flow, caution for one that needs review but doesn't block. Independent of isCurrent and isDisabled.

critical and caution mark where the problem is; they don't describe it. Keep the inline field errors on the step itself, and any summary on a review step, as the actual message.