Steps
PortedNumbered steps in an ordered list: done (a check), current (aria-current="step") or upcoming, and any of them can have an error. The steps are labels; the app moves between them with its own buttons, and with onSelect back to a done step. A polite live region says "Step n of m" when current changes, as focus stays on the app's Next button.
Step 2 of 3
- Done: Candidate
- Your relationship
- Role
import { Steps, type StepsItem } from "@etched/monet/steps";
const referral: StepsItem[] = [{ label: "Candidate" }, { label: "Your relationship" }, { label: "Role" }, { label: "Review" }];
export function Preview() {
return <Steps aria-label="Referral steps" steps={referral.slice(0, 3)} current={1} />;
}Installation
import { Steps } from "@etched/monet/steps";Examples
Wizard header
A row of steps above the form, with the count. Done steps are buttons that go back to them (onSelect); the app's own buttons move forward.
Step 2 of 4
- Your relationship
- Role
- Review
import { useState } from "react";
import { Button } from "@etched/monet/button";
import { Steps, type StepsItem } from "@etched/monet/steps";
const referral: StepsItem[] = [{ label: "Candidate" }, { label: "Your relationship" }, { label: "Role" }, { label: "Review" }];
export function WizardHeader() {
const [step, setStep] = useState(1);
return (
<div className="grid" style={{ maxWidth: "none" }}>
<Steps aria-label="Referral steps" steps={referral} current={step} showCount onSelect={setStep} />
<div className="row">
<Button disabled={step === 0} onClick={() => setStep(step - 1)}>
Back
</Button>
<Button variant="primary" disabled={step === referral.length} onClick={() => setStep(step + 1)}>
{step >= referral.length - 1 ? "Send referral" : "Next"}
</Button>
</div>
</div>
);
}Setup checklist
A column of steps, each with a line of help, like Topo setup.
Step 2 of 3
- Done: Install Topo
Add the extension from the Chrome Web Store.
- Confirm your account
Sign in to LinkedIn in the same Chrome profile.
- Share connections
Only the platform admin can see them. You can remove them at any time.
import { Steps, type StepsItem } from "@etched/monet/steps";
const topo: StepsItem[] = [
{ label: "Install Topo", description: "Add the extension from the Chrome Web Store." },
{ label: "Confirm your account", description: "Sign in to LinkedIn in the same Chrome profile." },
{ label: "Share connections", description: "Only the platform admin can see them. You can remove them at any time." },
];
export function SetupChecklist() {
return <Steps aria-label="Topo setup" orientation="vertical" steps={topo} current={1} showCount />;
}A step with an error
error marks a step that has a problem or is blocked, and its description says what is wrong. A done step with an error is still a button back to it. Without showCount, screen readers still hear "Step n of m" when the step changes.
Step 3 of 3
ana-ruiz-cv.pdf
Two candidates match this résumé. Go back and pick one.
- Confirm
Check the details, then add the candidate to the pipeline.
import { useState } from "react";
import { Steps, type StepsItem } from "@etched/monet/steps";
const intake: StepsItem[] = [
{ label: "Upload résumé", description: "ana-ruiz-cv.pdf" },
{ label: "Match candidate", description: "Two candidates match this résumé. Go back and pick one.", error: true },
{ label: "Confirm", description: "Check the details, then add the candidate to the pipeline." },
];
export function AStepWithAnError() {
const [step, setStep] = useState(2);
return <Steps aria-label="Intake steps" orientation="vertical" steps={intake} current={step} onSelect={setStep} />;
}Every step done
current at the number of steps marks them all done.
2 of 2 steps done
- Done: Select swarmers
- Done: Write messages
import { Steps, type StepsItem } from "@etched/monet/steps";
const swarm: StepsItem[] = [{ label: "Select swarmers" }, { label: "Write messages" }];
export function EveryStepDone() {
return <Steps aria-label="Create swarm steps" steps={swarm} current={swarm.length} showCount />;
}Accessibility
- With
onSelect, each done step is a native button:Tabreaches it, andEnterorSpacegoes back to it. Other steps take no focus. - An ordered
listnamed by the requiredaria-label. The current step hasaria-current="step". - The numbers and checks are hidden. Done steps say "Done:" and steps with
errorsay "Error:" before the label. - A polite live region says "Step 2 of 4" when
currentchanges, also withoutshowCount. - Move between steps with your own Back and Next buttons. On a step with
error, say what is wrong indescription.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| steps * | StepsItem[] | – | The steps, in order. |
| current * | number | – | The index of the current step, from 0. Steps before it are done, steps after it are upcoming. steps.length marks every step done. |
| aria-label * | string | – | Names the list, for example "Referral steps". |
| orientation | "horizontal" | "vertical" | "horizontal" | A row (a wizard header) or a column (a setup checklist). |
| showCount | boolean | – | Shows "Step n of m" above the steps. Screen readers hear it when the step changes, shown or not. |
| onSelect | (index: number) => void | – | Makes each done step a button that calls this with its index, to go back to it. The current and upcoming steps stay text. |
| countLabel | (current: number, total: number) => string | "Step 2 of 4", or "4 of 4 steps done" | The count's text, from current and the number of steps. Pass translated text, as for the other labels. |
| doneLabel | string | "Done" | Screen readers hear it before a done step's label. |
| errorLabel | string | "Error" | Screen readers hear it before the label of a step with an error. |