Progress Steps
- Stable
- WCAG 2.2 evidence
- RTL
A segmented progress indicator for a flow with a known number of steps, such as onboarding or a
form wizard: a header with "Step 2 of 5" and the step title above one segment per step. It is a role="progressbar" with
aria-valuenow, aria-valuemin, aria-valuemax and an aria-valuetext such as "Step 2 of 5", named by the title
(WCAG 1.3.1, 4.1.2). The state is written as text and drawn with three different segment looks (full, dimmed with an outline,
empty), never by colour alone (1.4.1). The only motion is a fade between states, behind motion-safe: (2.3.3). Use Stepper instead when the flow needs the names of every step. Presentational (no state, no React Aria): renders in
React Server Components; announceChanges adds a tiny client island. Consumer duties: the title, the translated value
text, and announcing the change (4.1.3) with announceChanges or by moving focus to the new step's heading.
import { ProgressSteps } from "@nexera-ui/react";- 8
- examples
- 8
- props
- 1
- live controls
- 1
- platform
- 9
- WCAG criteria
- 2
- blocks use it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { ProgressSteps } from "@nexera-ui/react";
<ProgressSteps />Examples 7
The same examples as Storybook, rendered live. Open Code to copy one.
Many steps
More steps and a later position than the Figma set shows: any whole number works.
import { ProgressSteps } from "@nexera-ui/react";
<ProgressSteps title="Company setup" steps={7} current={5} />;
Long title
Long titles wrap under the value text instead of being cut, and the bar stays one row of segments.
import { ProgressSteps } from "@nexera-ui/react";
<ProgressSteps
title="Upload your signed employment contract and identity documents"
steps={4}
current={3}
/>;
Name from aria label
The accessible name can come from aria-label when the flow's title is shown elsewhere; only the value text is visible.
import { ProgressSteps } from "@nexera-ui/react";
<ProgressSteps title="Personal details" steps={5} current={2} aria-label="Onboarding progress" />;
Translated value text
Translated value text: pass valueLabel; it is shown and read as aria-valuetext.
import { ProgressSteps } from "@nexera-ui/react";
<ProgressSteps title="Persönliche Daten" steps={5} current={2} valueLabel="Schritt 2 von 5" />;
Narrow container
The indicator fills the width of its container, here 240 px, and the header wraps with it.
import { ProgressSteps } from "@nexera-ui/react";
<div className="max-w-[15rem] rounded-md border border-default p-4">
<ProgressSteps title="Personal details" steps={5} current={3} />
</div>;
Right to left
Right-to-left: the label comes first at the right, and the segments fill from the right.
import { ProgressSteps } from "@nexera-ui/react";
<ProgressSteps title="التفاصيل الشخصية" steps={5} current={2} valueLabel="الخطوة 2 من 5" />;
Wizard
A wizard that moves with the buttons. announceChanges says the new step to screen readers (WCAG 4.1.3); leave it off when focus moves to the new step's heading.
import { useState } from "react";
import { Button, ProgressSteps } from "@nexera-ui/react";
function WizardExample({ steps = 5 }: { steps?: number }) {
const [current, setCurrent] = useState(1);
return (
<div className="flex max-w-[22.5rem] flex-col gap-6">
<ProgressSteps title="Company setup" steps={steps} current={current} announceChanges />
<div className="flex gap-2">
<Button
variant="secondary"
isDisabled={current === 1}
onPress={() => {
setCurrent((value) => Math.max(1, value - 1));
}}
>
Back
</Button>
<Button
isDisabled={current === steps}
onPress={() => {
setCurrent((value) => Math.min(steps, value + 1));
}}
>
Next
</Button>
</div>
</div>
);
}
export function Wizard() {
return <WizardExample title="Personal details" steps={3} current={1} />;
}
Props 8
Press "Try it" on a card to load that prop into the playground.
8 props shown
stepsNexeranumberNumber of segments. Any whole number from 1 works; the bar stays readable up to
about 8. Becomes aria-valuemax.
currentNexeranumberThe step the person is on, counted from 1. Segments before it are full, it is drawn
dimmed (in progress), the rest are empty. Values outside 1 to steps are clamped. Becomes aria-valuenow.
valueLabelNexerastringText shown as the label and announced as aria-valuetext. The state is always
written as text, so it never depends on the segment colours (WCAG 1.4.1). Translate it for your locale.
announceChangesNexerabooleanAnnounce the new valueLabel politely when current changes (WCAG 4.1.3), through React Aria's live announcer (this mounts
a small client component). Leave it off when your page already moves focus to the new step's heading, to avoid saying it
twice.
classNameNexerastringExtra classes for the root, merged last so they win over the defaults.
titleNexeraVisibleContentName of the step or flow. Shown in the header and used as the accessible name.
aria-labelNexerastringaria-labelledbyNexerastring* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
5 direct · 4 supporting- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.3.2Meaningful SequenceLevel A · supporting test
- 1.4.1Use of ColorLevel A · tested directly
- 1.4.11Non-text ContrastLevel AA · supporting test
- 1.4.12Text SpacingLevel AA · supporting test
- 2.3.3Animation from InteractionsLevel AAA · supporting test
- 3.1.2Language of PartsLevel AA · tested directly
- 4.1.2Name, Role, ValueLevel A · tested directly
- 4.1.3Status MessagesLevel AA · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<ProgressSteps className="shadow-sm" />Used in blocks
Related components
- AlertAn inline status message about a section or a task: tone icon, title, optional description, actions and close button.
- BannerA page-wide notice across the top of a page or app shell: tone icon, message, optional link and close button on a solid fill.
- CircularProgressShows progress as a ring with the value in the centre.
- EmptyStateExplains why a list, table or page has no content and what to do next.
- ProgressBarShows how far a task has progressed.
- SpinnerSmall loading indicator.
- SpinnerLabelA spinner with a status message.
- ToastGives the components below it a toast queue through `useToast()` and renders its `ToastRegion`.