Cmpnts

Menu

Molecules

Stepper

The steps of one task, showing which are done, which is current and which are left.


  1. Completed: Details
  2. Current: Agreement
  3. Payment
Code
HTML
<ol class="stepper" aria-label="Plot application">
  <li class="stepper__item is-complete">
    <div class="stepper__step">
      <span class="stepper__indicator" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Check"/></svg></span>
      <span class="stepper__title small-heading"><span class="sr-only">Completed: </span>Details</span>
    </div>
  </li>
  <li class="stepper__item" aria-current="step">
    <div class="stepper__step">
      <span class="stepper__indicator micro-heading" aria-hidden="true">2</span>
      <span class="stepper__title small-heading"><span class="sr-only">Current: </span>Agreement</span>
    </div>
  </li>
  <li class="stepper__item">
    <div class="stepper__step">
      <span class="stepper__indicator micro-heading" aria-hidden="true">3</span>
      <span class="stepper__title small-heading">Payment</span>
    </div>
  </li>
</ol>

Why it exists

A long task is easier to finish when you can see where you are and how much is left. A Stepper shows that and nothing more. It doesn’t run the task, keep track of it or decide what’s allowed next.

It is an ordered list, because the order is what it means. Its look says which steps are done, but the indicator is hidden from assistive technology, so each title starts with its state in words. The check and warning icons do the same job on screen, so state is never colour alone.

A step is only a Link or Button if someone can really go there. Most steps can’t be revisited, so a Stepper is plain text unless you say otherwise, and it only becomes navigation when its steps are links.

When to use

  • For the steps of one task, such as a checkout, a registration or a set-up guide.
  • Not a Breadcrumb (ancestors of a page): that is a Breadcrumb.
  • Not Pagination (pages of one list): that is Pagination.
  • Not for a bare percentage: a progress bar says how far a task has got without naming its steps.

Rules

  • Step element: a <div>; an <a> when the step is a page the user may revisit; a <button> in an in-page wizard (disable steps not yet reachable). Wrap the list in a <nav> only when its steps are links. Interactive steps have the focus ring and at least a 48px target.
  • State: aria-current="step" on the current item; .is-complete and .is-invalid on others. No .is-active.
  • Never colour alone (WCAG 1.4.1): the indicator is aria-hidden, so each title starts with its state in hidden text (“Completed: ”, “Current: ”, “Needs attention: ”). The indicator shows a check for complete and a warning icon for invalid; numbers otherwise, with .micro-heading.

Keyboard and screen readers

The browser provides all of this. Moving between wizard steps is the product’s script.

  • Plain steps can’t be focused, since there’s nothing to operate.
  • Tab reaches linked steps and enabled <button> steps. Enter follows a link, and Enter or Space presses a Button.
  • A disabled <button> step can’t be focused, so a keyboard user passes over it.
  • A screen reader reads each title with its state, from the hidden text, and takes the current step from aria-current="step".

Progress

  1. Completed: Details Verified
  2. Current: Agreement Sign the plot terms
  3. Payment Sliding scale
Code
HTML
<ol class="stepper" aria-label="Registration">
  <li class="stepper__item is-complete">
    <div class="stepper__step">
      <span class="stepper__indicator" aria-hidden="true">
        <svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Check"/></svg>
      </span>
      <span class="stepper__title small-heading"><span class="sr-only">Completed: </span>Details</span>
      <span class="stepper__description small-text">Verified</span>
    </div>
  </li>
  <li class="stepper__item" aria-current="step">
    <div class="stepper__step">
      <span class="stepper__indicator micro-heading" aria-hidden="true">2</span>
      <span class="stepper__title small-heading"><span class="sr-only">Current: </span>Agreement</span>
      <span class="stepper__description small-text">Sign the plot terms</span>
    </div>
  </li>
  <li class="stepper__item">
    <div class="stepper__step">
      <span class="stepper__indicator micro-heading" aria-hidden="true">3</span>
      <span class="stepper__title small-heading">Payment</span>
      <span class="stepper__description small-text">Sliding scale</span>
    </div>
  </li>
</ol>

Say Which Step Needs Attention

  1. Completed: Details Verified
  2. Needs attention: Soil agreement Signature missing
  3. Payment Sliding scale
Code
HTML
<ol class="stepper" aria-label="Plot agreement">
  <li class="stepper__item is-complete">
    <div class="stepper__step">
      <span class="stepper__indicator" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Check"/></svg></span>
      <span class="stepper__title small-heading"><span class="sr-only">Completed: </span>Details</span>
      <span class="stepper__description small-text">Verified</span>
    </div>
  </li>
  <li class="stepper__item is-invalid">
    <div class="stepper__step">
      <span class="stepper__indicator" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Warning"/></svg></span>
      <span class="stepper__title small-heading"><span class="sr-only">Needs attention: </span>Soil agreement</span>
      <span class="stepper__description small-text">Signature missing</span>
    </div>
  </li>
  <li class="stepper__item">
    <div class="stepper__step">
      <span class="stepper__indicator micro-heading" aria-hidden="true">3</span>
      <span class="stepper__title small-heading">Payment</span>
      <span class="stepper__description small-text">Sliding scale</span>
    </div>
  </li>
</ol>
Code
HTML
<nav aria-label="Checkout">
  <ol class="stepper" aria-label="Checkout steps">
    <li class="stepper__item is-complete">
      <a class="stepper__step" href="/checkout/shipping">
        <span class="stepper__indicator" aria-hidden="true"><svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Check"/></svg></span>
        <span class="stepper__title small-heading"><span class="sr-only">Completed: </span>Shipping</span>
      </a>
    </li>
    <li class="stepper__item" aria-current="step">
      <a class="stepper__step" href="/checkout/payment">
        <span class="stepper__indicator micro-heading" aria-hidden="true">2</span>
        <span class="stepper__title small-heading"><span class="sr-only">Current: </span>Payment</span>
      </a>
    </li>
    <li class="stepper__item">
      <div class="stepper__step">
        <span class="stepper__indicator micro-heading" aria-hidden="true">3</span>
        <span class="stepper__title small-heading">Review</span>
      </div>
    </li>
  </ol>
</nav>

Do and Don’t

DoDon’t
Start each title with its state in hidden text.Leave state to colour or the hidden indicator.
Use aria-current="step" on the current item.Add .is-active.
Use an <a> for a page the user may revisit, in a <nav>.Wrap a list of plain steps in a <nav>.
Disable <button> steps not yet reachable.Let people jump to a step they can’t complete.
Use --vertical in Sidebars and drawers.Squeeze a row into a narrow column and expect descriptions to show.

In Storybook

See also

  • Breadcrumb: The trail of pages above the current one, as a line of links.
  • Pagination: Links that move between the pages of one List.
  • Navigation Tree: Nested links to the sections of a site or a page, such as a docs Sidebar or a table of contents.
  • Progress and Meter: A bar for how far a task has got, or for a measurement within a known range.

Search the docs