Steps

Steps.Root shows a sequence of steps and where each one is, such as an agent's plan while it works, a checklist, or the steps of a form. Each Steps.Item takes a status: done, current, pending or error. The steps and their order are your data; Todae draws a marker for each status and the line that joins them.

On this page
<Steps.Root aria-label="Plan">
  {plan.map((step) => (
    <Steps.Item key={step.id} status={step.status}>
      {step.title}
    </Steps.Item>
  ))}
</Steps.Root>
  1. Done: Read the failing test
  2. In progress: Find where the date is parsed
  3. Not started: Write the fix
  4. Not started: Run the test suite

Parts

  • Steps.Root is an ol with role="list", so Safari keeps it a list without its markers.
  • Steps.Item is an li with a marker, then its content. Its status sets data-status and the marker: a done step shows the check glyph on a filled circle, the current step takes aria-current="step", a pending step shows an empty circle, and a step with an error shows the error glyph in the critical colors. pending is the default.

The markers and their colors come from the steps.marker.* tokens, the progress variant's current marker from steps.marker.progress.*, the text colors from steps.fg.*, the line from steps.line.*, and the space between steps from steps.gap.

Variants

variant on Steps.Root sets how the steps are drawn. The default, plan, is work that runs, such as an agent's plan: the current step shows a Loader spinner and done steps have their text struck through. progress is where a person is in a form, such as the steps of a Wizard: the current step shows a still ring with a dot in it, and done steps keep their text. The statuses, status words and aria-current are the same in both.

<Steps.Root variant="progress" aria-label="Sign-up steps">
  <Steps.Item status="done">Account</Steps.Item>
  <Steps.Item status="current">Workspace</Steps.Item>
  <Steps.Item>Review</Steps.Item>
</Steps.Root>
  1. Done: Account
  2. In progress: Workspace
  3. Not started: Review

Status words

The marker is hidden from screen readers. Each step starts with a visually hidden status word instead, so a screen reader reads "Done: Read the failing test". The words come from the stepDone, stepCurrent, stepPending and stepError strings of StringsProvider, "Done", "In progress", "Not started" and "Failed" in English. Pass statusLabel to an item for a word of your own, such as "Skipped" on a done step.

Accessible composition

Todae handles: An ordered list, a status word read before each step, aria-current="step" on the current step, and markers kept out of the accessible name.

You supply: A name for the list with aria-label or aria-labelledby when the page has more than one. An announcement when a step finishes or fails, if the person should hear it without moving to the list, such as through useAnnouncer. A status word that fits when the default doesn't.

Watch for: Showing a failure by color alone: say what went wrong in the step's text too. Putting a long step's details in the item, where the line-through of a done step in the plan variant crosses them all.

When to use

When: A plan or checklist whose steps run in order, each with a status. Where a person is in a form of several steps, with variant="progress".

When not: One running task → Loader or Progress. A trail of pages → Breadcrumbs.

Props

Steps.Root props
NameTypeDescription
variant"plan" | "progress"

plan is work that runs: the current step shows a spinner and done steps are struck through. progress is where a person is in a form: the current step shows a still ring with a dot and done steps keep their text. Sets data-variant.

Default: "plan"

Steps.Item props
NameTypeDescription
status"done" | "current" | "pending" | "error"

Sets data-status and the marker. A current step takes aria-current="step".

Default: "pending"

statusLabelstring

The hidden status word read before the step, in place of the stepDone, stepCurrent, stepPending or stepError string when not empty.