Aksara UI

Stepper

Stepper shows progress through a short, ordered flow and derives every step status from one active index.

import { Stepper } from '@aksornproject/aksara-ui'

Basic stepper

steps is an array of title and optional description, in flow order. activeStep is the 0-based index of the current step. Earlier steps are complete and later ones are incomplete. Each step is a Step in a list item.

  1. Your details
    Completed
    Name and email
  2. Address
    Where to send it
  3. Payment
    Not started
    Choose a method
<Stepper
  aria-label="Enrolment progress"
  steps={steps}
  activeStep={1}
  className="w-full"
/>

Moving through the flow

Stepper holds no state. Keep the index in your own state and pass it as activeStep. An index past the last step makes every step complete.

  1. Your details
    Name and email
  2. Address
    Not started
    Where to send it
  3. Payment
    Not started
    Choose a method
<div className="flex w-full flex-col gap-spacing-16">
  <Stepper
    aria-label="Enrolment progress"
    steps={steps}
    activeStep={active}
  />
  <div className="flex gap-spacing-8">
    <Button
      type="button"
      variant="secondary-brand"
      disabled={active === 0}
      onClick={() => setActive((step) => Math.max(step - 1, 0))}
    >
      Back
    </Button>
    <Button
      type="button"
      disabled={active === steps.length}
      onClick={() => setActive((step) => Math.min(step + 1, steps.length))}
    >
      Continue
    </Button>
  </div>
</div>

Not started and all complete

A negative activeStep means nothing has started. activeStep="complete" marks every step complete. Fractions truncate and NaN counts as 0, so every number is a valid input.

  1. Your details
    Not started
    Name and email
  2. Address
    Not started
    Where to send it
  3. Payment
    Not started
    Choose a method
  1. Your details
    Completed
    Name and email
  2. Address
    Completed
    Where to send it
  3. Payment
    Completed
    Choose a method
<div className="flex w-full flex-col gap-spacing-24">
  <Stepper aria-label="Not started" steps={steps} activeStep={-1} />
  <Stepper aria-label="All complete" steps={steps} activeStep="complete" />
</div>

Orientation and size

orientation="vertical" stacks the steps with an 8px gap. size sets sm, md or lg on every step. The defaults are horizontal and sm. Stepper never switches orientation by itself, so pick vertical for narrow screens.

  1. Your details
    Completed
    Name and email
  2. Address
    Completed
    Where to send it
  3. Payment
    Choose a method
  4. Review
    Not started
    Check and confirm
<Stepper
  aria-label="Enrolment progress"
  steps={steps}
  activeStep={2}
  orientation="vertical"
  size="md"
  className="w-[320px]"
/>

Narrow containers

Horizontal steps share the width equally, with a 160px minimum each and a 16px gap. They never wrap. Below that width the list overflows, so the page owns the scrolling.

  1. Your details
    Completed
    Name and email
  2. Address
    Where to send it
  3. Payment
    Not started
    Choose a method
  4. Review
    Not started
    Check and confirm
<div className="w-[326px] overflow-x-auto">
  <Stepper aria-label="Enrolment progress" steps={steps} activeStep={1} />
</div>

Custom styles

indicator, titleClassName and descriptionClassName apply to every step. Each takes one value for every status or a map keyed by status. Per-step differences need a hand-written list of Step parts.

  1. Section A
    Completed
    Multiple choice
  2. Section B
    Short answers
  3. Section C
    Not started
    Essay
<Stepper
  aria-label="Exam sections"
  steps={steps}
  activeStep={1}
  titleClassName={{ complete: 'text-color-text-secondary' }}
  descriptionClassName={typography('supporting-regular')}
  className="w-full"
/>

Accessibility

  • The root is an ol with role="list", which keeps list semantics in Safari. Give it an aria-label when the page has more than one flow.
  • Only the current step's list item has aria-current="step".
  • Complete and incomplete steps add visually hidden words after the title, "Completed" and "Not started" by default. Localise them with statusLabels.
  • Indicators and segments are decorative and aria-hidden.
  • Steps are not tabs, buttons or links. Put navigation controls outside the list and keep titles and descriptions noninteractive.

API

Stepper

Prop

Type

StepperItem

Prop

Type

Edit on GitHub

On this page