Stepper Nav
Navigate a flow that spans pages, with links back to completed steps.
import { StepperNav } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use it at the top (or down the side) of a flow where each step is its own page: checkout, onboarding, workspace setup. It shows where the reader is and lets them go back to any step they've done. It doesn't run the flow: validation, saving and what "Continue" does stay with your app, and upcoming steps can't be jumped to. When the steps live on one page and the component should own them, use a Wizard. To show progress without links, use a Stepper on its own.
import { StepperNav } from '@youj/react'
const steps = [
{ id: 'account', title: 'Account', description: 'Email and password' },
{ id: 'workspace', title: 'Workspace', description: 'Name and URL' },
{ id: 'plan', title: 'Plan' },
{ id: 'invite', title: 'Invite', optional: true },
]
export function SetupProgress({ step }: { step: number }) {
return <StepperNav aria-label="Setup" steps={steps} current={step} href={(i) => `/setup/${steps[i]!.id}`} />
}current is the index of the step the reader is on, usually read from the route. href maps a step to its page. The done steps and the current one become links, and the ones ahead stay plain text. Set current to steps.length once the flow is done, and every step shows its check.
Each step is a Stepper step: a title, an optional description, optional to add "Optional" under the title, and error to mark a step that needs another look. onNavigate fires as a step link is followed, which is where a client-side router takes over.
Description
A four-step setup row with Back and Continue buttons; finished steps become links back.
The horizontal row keeps its discs and connectors on narrow screens and drops the titles below sm, so four or five steps still fit in one line. The titles stay in the accessible name. Pass compact={false} to keep them visible, or switch to vertical on phones.
The same navigation stacked down the side of a checkout, beside the content for the current step.
orientation="vertical" stacks the steps down the side of the page, next to the form they describe, with the connectors running between the discs.
Code
stepper-nav-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propssteps, current, href… (6)
Props
| Prop | Type | |
|---|---|---|
stepsRequired | readonly StepperStep[] | – |
currentRequired | numberIndex of the current step. | – |
hrefRequired | (index: number) => stringThe page of step | – |
onNavigate | (index: number) => voidFires as a step link is followed, e.g. for client-side routing. | – |
orientation | 'horizontal' | 'vertical'default 'horizontal' | 'horizontal' |
compact | booleanHide titles below default true | true |
Other props pass through: extends ComponentProps<'nav'>. | ||
MotionConnector fills, connector drains, check… · reduced motion
Motion
The motion is Stepper's.
| Moment | Tokens | ||
|---|---|---|---|
| Connector fillsas a step completes, scaling along the line from the finished step | duration.slowease.standard340ms · cubic-bezier(0.2, 0, 0, 1) | 340mscubic-bezier(0.2, 0, 0, 1) | |
| Connector drainswhen you go back, from wherever the fill is | duration.slowease.standard340ms · cubic-bezier(0.2, 0, 0, 1) | 340mscubic-bezier(0.2, 0, 0, 1) | |
| Checkdraws in on a finished step | duration.slowease.emphasized340ms · cubic-bezier(0.6, 0, 0.1, 1) | 340mscubic-bezier(0.6, 0, 0.1, 1) | |
| Disc and title colorupcoming, current, complete or error | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Connectors fill and drain at once, and checks appear already drawn.
Reduced motion
The connectors fill and drain at once, and a finished step's check appears already drawn. Colors change instantly. The links, statuses and names are unchanged.
AccessibilityARIA, focus
Accessibility
- It's a
navlandmark named "Progress" by default. Name it after the flow witharia-label("Setup", "Checkout"). - The steps are an ordered list. The current step carries
aria-current="step", and every step's name ends with its status ("Workspace, current step", "Account, completed", "Plan, not started"), so the progress reads the same without the colors. - Done steps and the current one are links. Upcoming steps aren't focusable, since they can't be reached yet.
- Titles hidden below
smare still in the accessible name.