Dots

Step Header

The top of a multi-step flow with back or close, a step counter, segmented progress, and the step heading.

Step 2 of 5

Where do you live?

We send the card to this address.

import {
  StepHeader,
  StepHeaderAction,

The StepHeader component sits at the top of a multi-step flow such as ordering a card, verifying an identity, or sending a transfer. It shows where the user is, lets them go back or leave, and states what the current step asks for. Use StepHeaderCount with StepHeaderProgress for longer flows, and StepHeaderSteps when a short flow has three or four named steps.

Installation

pnpm dlx shadcn@latest add @dots/step-header

Usage

import {
  StepHeader,
  StepHeaderBack,
  StepHeaderBar,
  StepHeaderContent,
  StepHeaderCount,
  StepHeaderHeading,
  StepHeaderProgress,
} from "@/components/ui/step-header"
<StepHeader>
  <StepHeaderBar>
    <StepHeaderBack onPress={goBack} />
    <StepHeaderCount step={2} total={5} />
  </StepHeaderBar>
  <StepHeaderProgress step={2} total={5} />
  <StepHeaderContent>
    <StepHeaderHeading>Where do you live?</StepHeaderHeading>
  </StepHeaderContent>
</StepHeader>

Composition

Use the following composition to build a step header:

StepHeader
├── StepHeaderBar
│   ├── StepHeaderBack or StepHeaderClose
│   ├── StepHeaderCount or StepHeaderTitle
│   └── StepHeaderAction or StepHeaderClose side="end"
├── StepHeaderProgress or StepHeaderSteps
└── StepHeaderContent
    ├── StepHeaderHeading
    └── StepHeaderDescription

Features

  • A three-column bar that keeps the counter or title centered with or without a button on each side
  • Segmented progress built on the React Aria ProgressBar, read as "Step 2 of 5"
  • Partial fill of the current segment through stepProgress for a step with inner screens
  • Named steps for short flows, with a check on done steps and aria-current="step" on the current one
  • Back and close buttons with default labels, and a text action slot for "Skip" or "Save and exit"
  • A heading level you can set to fit the page outline

First step

On the first step there is nothing to go back to, so put StepHeaderClose at the start of the bar instead of StepHeaderBack.

Step 1 of 4

Choose a card

Virtual cards are ready in two minutes.

import {
  StepHeader,
  StepHeaderBar,

Optional step

Pass note to StepHeaderCount to mark a step as optional and add a StepHeaderAction to skip it. Set stepProgress to fill part of the current segment when a step has its own inner screens. When you replace the counter wording through children, pass the same text as valueLabel to StepHeaderProgress.

3 of 4, Optional

Add to your phone

Pay with your phone before the physical card arrives.

import {
  StepHeader,
  StepHeaderAction,

Named steps

For a short flow of up to four steps, show the step names with StepHeaderSteps and the flow name with StepHeaderTitle. Use side="end" to put the close button at the end of the bar.

New transfer
  1. Done: Recipient
  2. Amount
  3. Review
import {
  StepHeader,
  StepHeaderBack,

Changing steps

Keep the button that moves forward, such as Continue, in the content below the header; StepHeaderAction is for a secondary action such as "Skip". When the step changes in place, the pressed Back or Continue button may unmount. Give StepHeaderHeading a ref and tabIndex={-1}, and focus it in an effect keyed on the step. Focus is not lost and the new step is read.

Step 1 of 4

Your name

As it appears on your ID.

"use client"

import * as React from "react"
const headingRef = React.useRef<HTMLHeadingElement>(null)
// Set on a step change, so the first render does not take focus.
const changed = React.useRef(false)
 
React.useEffect(() => {
  if (changed.current) headingRef.current?.focus()
}, [step])
 
const go = (next: number) => {
  changed.current = true
  setStep(next)
}
 
<StepHeaderBack onPress={() => go(step - 1)} />
<StepHeaderHeading ref={headingRef} tabIndex={-1}>
  {current.heading}
</StepHeaderHeading>

Accessibility

StepHeaderProgress renders a React Aria ProgressBar with role="progressbar", its value, and a value text of "Step 2 of 5". The segments are hidden from assistive tech. StepHeaderBack, StepHeaderClose, and StepHeaderAction render a Button, so they work with mouse, touch, and keyboard.

Labels

StepHeaderBack and StepHeaderClose are icon-only and default to aria-label="Back" and aria-label="Close". Pass your own aria-label when the app is translated or the close button means something more specific, such as "Cancel transfer". StepHeaderProgress defaults to aria-label="Progress" and StepHeaderSteps to aria-label="Steps".

Named steps

StepHeaderSteps renders an ordered list. Done steps get a visually hidden "Done:" prefix and the current step gets aria-current="step", so the state is not conveyed by the check or the color alone.

Focus on step change

Move focus to StepHeaderHeading after each step change, as shown in Changing steps. Do not focus it on the first render.

API Reference

StepHeader

The root container. Make it sticky from the outside if the bar should stay visible while the content scrolls.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the root element.
...propsReact.ComponentProps<"div">-Props spread to the <div>.

StepHeaderBar

The top row with three columns. The side columns never squeeze their buttons; the center truncates on narrow screens.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the bar.
...propsReact.ComponentProps<"div">-Props spread to the <div>.

StepHeaderBack

Goes back one step. Renders an icon-only ghost Button.

PropTypeDefaultDescription
side"start" | "end""start"Which side of the bar the button sits on.
aria-labelstring"Back"The accessible name of the button.
...propsOmit<React.ComponentProps<typeof Button>, "children" | "variant" | "size">-Props spread to the underlying Button.

StepHeaderClose

Leaves the flow. Renders an icon-only ghost Button.

PropTypeDefaultDescription
side"start" | "end""start"Which side of the bar the button sits on.
aria-labelstring"Close"The accessible name of the button.
...propsOmit<React.ComponentProps<typeof Button>, "children" | "variant" | "size">-Props spread to the underlying Button.

StepHeaderAction

A text action at the end of the bar, such as "Skip" or "Save and exit". Renders a Button and accepts all of its props.

PropTypeDefaultDescription
variantReact.ComponentProps<typeof Button>["variant"]"ghost"The button variant.
sizeReact.ComponentProps<typeof Button>["size"]"sm"The button size.
...propsReact.ComponentProps<typeof Button>-Props spread to the underlying Button.

StepHeaderCount

The "Step 2 of 5" counter in the center of the bar.

PropTypeDefaultDescription
stepnumber-The current step, starting at 1. Required.
totalnumber-The number of steps. Required.
noteReact.ReactNode-A short note after the counter, such as "Optional".
childrenReact.ReactNode-Replaces the default "Step 2 of 5" wording, such as "2 of 5" or a translation.
classNamestring-Additional classes to apply to the counter.
...propsOmit<React.ComponentProps<"span">, "children">-Props spread to the <span>.

StepHeaderTitle

The flow name in the center of the bar, used with named steps.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the title.
...propsReact.ComponentProps<"span">-Props spread to the <span>.

StepHeaderProgress

Segmented progress built on the React Aria ProgressBar. Passed and current segments are filled, the rest show the track.

PropTypeDefaultDescription
stepnumber-The current step, starting at 1. Required.
totalnumber-The number of steps. Required.
stepProgressnumber-How much of the current step is done, from 0 to 1. Without it the current segment is filled.
valueLabelReact.ReactNode"Step {step} of {total}"The value text read by assistive tech.
aria-labelstring"Progress"The accessible name. Not applied by default when aria-labelledby is set.
aria-labelledbystring-The id of an element that names the progress bar.
classNamestring-Additional classes to apply to the progress bar.
...propsOmit<ProgressBarProps, "children" | "className" | "style" | "value" | "minValue" | "maxValue">-React Aria ProgressBar props, such as id.

StepHeaderSteps

Named steps for short flows, rendered as an ordered list.

PropTypeDefaultDescription
stepsReact.ReactNode[]-The step names, up to four. Required.
stepnumber-The current step, starting at 1. Required.
aria-labelstring"Steps"The accessible name of the list.
classNamestring-Additional classes to apply to the list.
...propsOmit<React.ComponentProps<"ol">, "children">-Props spread to the <ol>.

StepHeaderContent

Wraps the step heading and description under the progress.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the content slot.
...propsReact.ComponentProps<"div">-Props spread to the <div>.

StepHeaderHeading

The question or task of the step, such as "Where do you live?".

PropTypeDefaultDescription
level1 | 2 | 32The heading level in the page outline.
classNamestring-Additional classes to apply to the heading.
...propsReact.ComponentProps<"h2">-Props spread to the heading, including ref and tabIndex.

StepHeaderDescription

A short line under the heading that explains why the step is needed.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the description.
...propsReact.ComponentProps<"p">-Props spread to the <p>.