// preview in
saved for every page

Stepper

Shows where people are in a flow with a fixed order, such as a checkout or a sign-up, and how much is left. It is a numbered list, not navigation.

Pattern Ordered list with aria-current="step"Client componentSource ↗
minimal · light · #3fa34d
  1. AccountEmail and password
  2. CompanyTax ID and address
  3. ReviewCheck and activate
orientation

Installation

Set up Camaleo once (Installation), then import what you need. It is a client component: each step reads its status from the stepper.

import { Stepper, Step, StepIndicator, StepTitle, StepDescription, StepSeparator } from "@camaleo/react";

Anatomy

A Stepper is an <ol> and each Step an <li>, so screen readers say "list, 4 items" and the position of each one. Set activeStep on the stepper and every step works out its status: done before it, current at it, upcoming after it. The line between steps is drawn by the step itself, or by a StepSeparator placed last in it; the indicator is hidden from screen readers, so the title carries the meaning. A horizontal stepper narrower than 30rem (a container query, not the viewport) hides every title but the current one.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d
Checkout3 items · $54.80
  1. Cart, done
  2. Shipping
  3. Payment
  4. Review
  1. Cart
  2. Shipping
  3. Payment
  4. Review

Step 1 of 4: Cart

Cerrado beans 500 g, paper filters and a stoneware mug. Subtotal $54.80.

Back and Continue

Press Continue. Focus moves to the new step's heading, so a screen reader says "Step 2 of 4: Shipping" and keyboard users start at the top of the new form.

  1. CartDone
  2. ShippingIn progress
  3. PaymentNot started

State in words

Color and a check mark are not enough. Name the list with aria-label and give each state a word, visible or in VisuallyHidden.

  1. , done
  2. , done
  3. Payment
  4. Review, not started

Go back to a finished step

Click Cart. Only steps people already reached are links; steps ahead stay plain text, because their data doesn't exist yet.

  1. Cart, done
  2. Shipping, done
  3. Payment, needs attentionCard declined
  4. Review

Card declined. Try another card.

A step with an error

status="error" turns the step red with a cross and keeps aria-current when it is the active step. Say what went wrong in words too, because color and the icon are not announced.

  1. Ordered, done
  2. Packed, waiting for the carrier
  3. Delivered

One line styled apart

Place a StepSeparator last in a step when one line needs its own look, such as a dashed line to a step that waits on someone else.

  1. Store profile, doneName, logo and address of Grão Coffee Co.
  2. Add products, done12 of 12 imported from your spreadsheet.
  3. Connect paymentsLink a bank account to receive sales.
  4. Open the storePick a domain and publish.

Vertical, with descriptions

A column has room for a line under each step. Use it in a sidebar or for a setup checklist people come back to.

  1. Create account, doneana@graocoffee.com
  2. Choose a plan, donePro, $12/mo
  3. Invite your teamOptionalAdd people now or later in Settings.
  4. Start sellingYour dashboard is ready.

Optional step

Mark it with a badge, not just lighter text, so people know they can move on without it.

  1. Cart, done
  2. Shipping
  3. Payment
  4. Review

Compact on phones

Below 30rem of width, a horizontal stepper keeps only the current title on screen; the others stay in the list for screen readers. Add "Step 2 of 4" above it so people still see how long the flow is.

In context

These are whole pieces of UI you can copy, in the skin you picked.

Grão Coffee Co.3 items · $54.80
  1. Cart, done
  2. Shipping
  3. Payment
  4. Review

Shipping address

CheckoutCard · Stepper · Field · Input · Button

Set up your store

2 of 4 done
  1. Store profile, done
  2. Add products, done
  3. Connect payments
  4. Open the store
Connect payments

Sales go to this account every business day. It takes about 3 minutes.

Store setupCard · Badge · Stepper · Field · Button
Order #4821Placed on 03/14/2026 · 3 itemsOn the way
  1. Ordered, done03/14, 9:12 AM
  2. Packed, done03/14, 4:40 PM
  3. Out for deliveryExpected today by 6 PM
  4. DeliveredSignature required
Order trackingCard · Badge · Stepper · Button

Guidelines

  1. Business, done
  2. Documents
  3. Shipping
  4. Launch
DoThree to five steps, one or two words each.

People read the whole flow at a glance and know how far they are from the end.

  1. Tell us about your business and its owners, done
  2. Upload your documents
  3. Configure shipping zones and rates
  4. Review and launch your store
Don’tSentences for labels.

They don't fit side by side, so the stepper hides all but the current one and people can't see what's ahead. Put the details in each step's heading.

Notifications: choose what we email you about.
DoTabs for sections in any order.

Settings pages have no first or last section, and nothing is ever "done".

  1. Profile
  2. Notifications
  3. Billing
Notifications: choose what we email you about.
Don’tA stepper for free navigation.

Numbers and check marks promise an order and an end that don't exist, and the steps can't be clicked.

Props

PropTypeDefaultDescription
orientationStepperOrientation"horizontal"Lays the steps out in a row or a column. Vertical fits descriptions and narrow sidebars.
activeStepnumber—Index (from 0) of the current step. Steps before it are completed, the one at it is current and the ones after it are upcoming, unless a Step sets its own status.
aria-labelstring—Names the list, for example "Checkout progress".

Step takes status ("completed" · "current" · "upcoming" · "error"), or the shorthands completed and current; without them, the status comes from activeStep, and is "upcoming" when there is none. StepIndicator takes its step's status, or its own status; with "completed" it shows a check mark and with "error" a cross instead of its children. The rest are the native props of <ol>, <li> and <span>.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the stepper itself.

Attributes

data-orientationhorizontal · vertical (on the stepper)
data-statuscompleted · current · upcoming · error (on the step and the indicator)
aria-current"step" on the current step

Tokens it reads

Color

--cml-accent--cml-accent-fg--cml-border-control--cml-brand--cml-brand-50--cml-brand-700--cml-danger--cml-fg--cml-fg-secondary--cml-stepper-completed-bg--cml-stepper-completed-fg--cml-stepper-current-bg--cml-stepper-current-border--cml-stepper-current-fg--cml-stepper-error-border--cml-stepper-error-fg--cml-surface

Shape & size

--cml-border-width

Type & motion

--cml-font-body--cml-stepper-completed-line--cml-stepper-line

This component only

--cml-step-indicator-bg--cml-step-indicator-fg--cml-step-indicator-radius--cml-step-indicator-size
/* square indicators and a thicker line in the checkout */
.checkout [data-slot="stepper"] {
  --cml-step-indicator-radius: 6px;
  --cml-stepper-line: 3px solid var(--cml-border-control);
}

Accessibility

TabSkips the stepper unless a step holds a link or a button; then it moves to it, in order.
EnterOn a step link, goes back to that step.
Was this page helpful? · Edit this page on GitHub