Multi-step progress indicator (stepper / wizard) component.
Shows users where they are in a multi-step process such as a checkout
flow, onboarding wizard, or form wizard. Each step has one of three
statuses: complete, active, or upcoming. CSS-only — no JavaScript
hook is required.
Sub-components
| Component | Element | Purpose |
|---|---|---|
step_tracker/1 | <ol> | Ordered list container with orientation support |
step/1 | <li> | Individual step with circle, label, and description |
Step statuses
| Status | Circle style | Label style | ARIA |
|---|---|---|---|
complete | bg-primary + check icon | font-medium | — |
active | bg-primary + ring-2 ring-primary | font-semibold | aria-current="step" |
upcoming | outlined border-2 border-border | text-muted-foreground | — |
Horizontal step tracker (default)
The most common layout — shown at the top of multi-step forms:
<.step_tracker>
<.step status="complete" label="Cart" step={1} />
<.step status="complete" label="Shipping" step={2} />
<.step status="active" label="Payment" step={3} description="Enter your card details" />
<.step status="upcoming" label="Review" step={4} />
<.step status="upcoming" label="Confirm" step={5} />
</.step_tracker>Vertical step tracker
Vertical orientation works well in sidebars or narrower panels. Add
orientation="vertical" to the container:
<.step_tracker orientation="vertical">
<.step status="complete" label="Create account" step={1} />
<.step status="active" label="Verify email" step={2} description="Check your inbox" />
<.step status="upcoming" label="Complete profile" step={3} />
</.step_tracker>Multi-step checkout example
A typical e-commerce checkout integrating with LiveView state:
defmodule MyAppWeb.CheckoutLive do
use MyAppWeb, :live_view
@steps ~w(cart shipping payment review)
def mount(_params, _session, socket) do
{:ok, assign(socket, current_step: "shipping")}
end
defp step_status(step, current) do
steps = @steps
current_idx = Enum.find_index(steps, &(&1 == current))
step_idx = Enum.find_index(steps, &(&1 == step))
cond do
step_idx < current_idx -> "complete"
step_idx == current_idx -> "active"
true -> "upcoming"
end
end
endTemplate:
<.step_tracker>
<.step status={step_status("cart", @current_step)} label="Cart" step={1} />
<.step status={step_status("shipping", @current_step)} label="Shipping" step={2} />
<.step status={step_status("payment", @current_step)} label="Payment" step={3} />
<.step status={step_status("review", @current_step)} label="Review" step={4} />
</.step_tracker>Accessibility
- The
<ol>root hasaria-label="Progress steps"to announce context. - The active step
<li>carriesaria-current="step"so screen readers announce "current step, [label]" giving users clear orientation. - Completed steps receive no special ARIA; their check icon is
aria-hiddenas the status is conveyed by the label context.
Summary
Functions
Renders an individual step.
Displays:
- A circle on the left: check icon for
complete, step number foractive/upcoming, or empty ifstepisnil. - A label beside the circle, weight varies by status.
- An optional description in muted text below the label.
The active step receives aria-current="step" so assistive technologies
announce it as the current step in the sequence.
Examples
<%!-- Completed step --%>
<.step status="complete" label="Account setup" step={1} />
<%!-- Active step with description --%>
<.step status="active" label="Payment details" step={2}
description="Your card is charged only after review." />
<%!-- Upcoming step --%>
<.step status="upcoming" label="Confirm order" step={3} />Attributes
status(:string) (required) - Step status. Controls visual styling and ARIA attribute. One of"complete","active", or"upcoming". Must be one of"complete","active", or"upcoming".label(:string) (required) - Primary step label shown beside the circle (e.g."Shipping").step(:integer) - Step number displayed inside the circle forupcomingandactivestates. Whennil, the circle is empty for non-complete steps. Defaults tonil.description(:string) - Optional secondary text shown below the label. Useful for brief instructions on the active step. Defaults tonil.class(:string) - Additional CSS classes applied to the<li>element. Defaults tonil.- Global attributes are accepted. HTML attributes forwarded to the
<li>element.
Renders the step tracker container.
Wraps step/1 items in an <ol> (ordered list) with the appropriate
flex layout for the chosen orientation.
Choose orientation="horizontal" for a top-of-page progress bar and
orientation="vertical" for a sidebar or panel layout.
Attributes
orientation(:string) - Layout direction:"horizontal"(default, flex-row) or"vertical"(flex-col). Defaults to"horizontal". Must be one of"horizontal", or"vertical".class(:string) - Additional CSS classes applied to the root<ol>element. Defaults tonil.- Global attributes are accepted. HTML attributes forwarded to the root
<ol>element.
Slots
inner_block(required) - Should containstep/1children.