Stepper
The root of a step sequence — a row of steps on wide viewports, a two-line text summary on narrow ones.
Usage
import { Stepper, StepperItem } from '@acronis-platform/ui-react';Stepper renders a sequence two ways and lets CSS pick one:
- At 1024px and above — the
StepperItemchildren you pass, in a start-aligned row that wraps. - Below 1024px — a two-line text summary instead:
Step 3 of 5: Choose a plan, thenNext: Confirm and pay. No step items at all.
Both subtrees are always in the DOM and a real viewport media query (Tailwind's
lg:) displays one and hides the other — there is no ResizeObserver, no
measuring pass, and nothing mounts or unmounts as the window resizes. Because the
component cannot see which layout is live, you supply both: the children for
the row, and currentStep / totalSteps / current / next for the summary.
On the last step, omit next and the whole Next: … line is left out rather
than rendered empty.
Every string the component generates itself — stepLabel ("Step"), ofLabel
("of"), nextLabel ("Next:"), and separatorLabel (": ", the punctuation
before the step's name) — is a prop so it can be translated. Everything else it
renders is yours.
Figma names the two variants 0-1024 and >1025. The implementation uses the
kit's pinned lg breakpoint — exactly 1024px — so 1024px renders the wide
row, one pixel lower than the Figma label implies. That keeps the component
on the shared breakpoint scale rather than minting a bespoke 1025px query.
As of the 2026-08-24 Figma sync, this component consumes a dedicated
--ui-stepper-breakpoint-* token tier from @acronis-platform/tokens-pd —
the summary's line gap, the item row's gap, and both summary text colors are
Stepper-owned tokens rather than borrowed from the semantic scale, the same
treatment StepperItem carries.
Examples
A full sequence:
<Stepper
currentStep={2}
totalSteps={3}
current="Choose a plan"
next="Confirm and pay"
>
<StepperItem
variant="completed"
label="Create an account"
avatar={
<Avatar color="green" className="[box-shadow:none]">
<CheckIcon size={16} />
</Avatar>
}
/>
<StepperItem
variant="current"
label="Choose a plan"
avatar={
<Avatar
color="blue"
className="[box-shadow:none] text-[var(--ui-stepper-item-current-label-color)]"
>
<AvatarFallback>2</AvatarFallback>
</Avatar>
}
/>
<StepperItem
variant="future"
label="Confirm and pay"
avatar={
<Avatar
color="gray"
className="[box-shadow:none] text-[var(--ui-stepper-item-future-label-color)]"
>
<AvatarFallback>3</AvatarFallback>
</Avatar>
}
/>
</Stepper>Avatar always paints a 2px outset ring meant to separate overlapping
avatars in an AvatarGroup. Figma's Stepper avatars carry no such stroke,
so left on, the ring shows as an unwanted halo on a filled step container.
Switch it off with className="[box-shadow:none]" on each composed
Avatar, as shown above — see StepperItem
for the full note.
The last step — no next, so the compact layout shows a single line:
<Stepper currentStep={3} totalSteps={3} current="Confirm and pay">
{/* … */}
</Stepper>Translated summary copy:
<Stepper
currentStep={2}
totalSteps={3}
current="Choisissez une formule"
next="Confirmer et payer"
stepLabel="Étape"
ofLabel="sur"
nextLabel="Suivante :"
separatorLabel=" : "
>
{/* … */}
</Stepper>Accessibility
Only one layout is ever announced: the hidden one is display: none, which
removes it from the accessibility tree, so a screen-reader user hears the text
summary below 1024px and the step items above it — never both. The root is a
plain <div> with no role and no tab stops of its own; if the sequence should
announce as an ordered list, or the current step as aria-current="step",
compose that on the StepperItem children via their render prop.
API Reference
Prop
Type