AppStepper
Where the user is in a multi-step flow — compact inside a card, or wide as a masthead.
<app-stepper><app-step label="…" status="done" /></app-stepper><app-stepper> answers three questions at once: where am I, what have I finished, and how much is left. A wizard without one leaves the user unable to judge whether to start now or come back later.
It is one component with two variants, not two components — the states (done / active / pending / error), the tick-instead-of-number rule and the link behaviour are identical; only the layout differs. Either variant can run orientation="vertical".
Playground
Every attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the stepper above it.
Compact
The default. A numbered circle above its label, with a connecting line behind the circles. Sized to sit inside a form card, above the fields for the current step.
Show code
<app-stepper>
<app-step label="Add site" status="done" />
<app-step label="Add zones" status="done" />
<app-step label="Risk assessment" status="active" />
<app-step label="Create report" />
</app-stepper>
Journey bar
The wide variant — a large dot beside a “STEP 2” index and the step name, in a bordered bar. For a page masthead above the whole flow, where there is room for full labels.
xl the label pairs no longer fit side by side, so the bar becomes a vertical list and the connectors go away.Show code
<app-stepper variant="journey">…</app-stepper>
Deriving state from active-step
Instead of hand-setting done / active / pending on every step, set a single active-step index and the statuses are derived — steps before it are done, the one at it is active, the rest pending. A step's own explicit status still wins.
Show code
<app-stepper active-step="2">
<app-step label="Add site" />
<app-step label="Add zones" />
<app-step label="Risk assessment" />
<app-step label="Create report" />
</app-stepper>
A failed step
Give a step status="error" and it turns red with an alert glyph — an invalid or failed stage the user must return to. It carries no aria-current (the user is being sent back, not standing there).
Show code
<app-step label="Payment" status="error" />
Descriptions & icons
A step can carry a secondary description line under its label, and its own icon in place of the number. A done or error step keeps its tick / alert — the custom icon shows only while pending or active.
Show code
<app-step label="Payment" description="Card or invoice" icon="credit-card" status="active" />
Vertical
orientation="vertical" stacks the steps down a side rail, the connector running between the circles. For a narrow column, a drawer, or a settings wizard.
Show code
<app-stepper orientation="vertical">
<app-step label="Account" description="Email & password" status="done" />
<app-step label="Company" description="Legal name & tax id" status="active" />
<app-step label="Billing" description="Card or invoice" />
<app-step label="Review" />
</app-stepper>
Clickable steps
React's onStepClick makes each step a button that reports its index, for a JS-driven wizard whose navigation lives in client state rather than the URL. A server-rendered page has no client state to drive, so there is no Razor equivalent.
href on each <app-step> for a revisitable step here instead — see “Revisitable steps” below.Jump to any step
When every stage can be visited in any order, give each <app-step> an href and drive active-step from the request. A click anywhere on a step, its circle, its title or its description, goes straight to that step, forwards or back.
active-step.Show code
<app-stepper variant="journey" active-step="@Model.Step">
<app-step label="Account" href="?step=0" />
<app-step label="Payment" icon="credit-card" href="?step=1" />
<app-step label="Delivery" icon="map-pin" href="?step=2" />
<app-step label="Confirm" icon="check-circle" href="?step=3" />
</app-stepper>
Revisitable steps
Give a step an href and it becomes a link back to that stage. Only do this for a stage the user may actually return to — a link to a step that would reset their progress is worse than no link.
Show code
<app-step label="Add site" status="done" href="/projects/1/site" />
When to use
Use it when
- A task is split across several screens and the user needs to see the shape of it.
- Steps have a fixed order and a known count.
- Finished steps matter — the user may want to go back and check one.
Reach for something else when
- The sections are alternative views switched freely. → app-tabs
- It is one long form on a single screen. → .fld-section heading
- The number of steps is unknown or changes. → a progress message
- You are showing progress of a background job. → app-spinner
Best practices
Every option
The whole surface of the component, one cell per value — every status, both variants, both orientations, and the combinations that behave specially.
variant — both
variant="steps"
variant="journey"
step status — every value
status="done"
status="active"
status="pending"
status="error"
orientation — vertical, both variants
variant="steps" orientation="vertical"
variant="journey" orientation="vertical"
active-step derivation — every index
active-step="0"
active-step="1"
active-step="2"
active-step="3"
per-step icon (done/error override it)
icon="credit-card" (pending)icon="credit-card" status="done" (icon suppressed by the tick)icon="credit-card" status="error" (icon suppressed by the alert)per-step description
variant="steps" — description under the labelvariant="journey" — description inside the text block(no description)href — plain, link, active link
(no href — renders a div)href — renders an <a>href + status="active" — aria-current on the linkonStepClick — React-only
(no Razor equivalent — renders the same as no href)
onStepClick has no Razor equivalent — a server-rendered page has no client state to drive. Use href for a revisitable step there instead.empty steps
<app-stepper />Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| variant | steps | journey | steps | Compact (circle above label) or wide (dot beside index + label). Pick by available width. |
| orientation | horizontal | vertical | horizontal | Vertical stacks the steps down a side rail — for a narrow column or drawer. |
| active-step | int | -1 (no derivation) | When set, statuses are derived from the index (before it done, at it active, after it pending). A step's explicit status still wins. |
| label | string | Progress | Accessible name for the nav element. |
| (app-step) label | string | — | The step's label. Each <app-step> child is one step, in order. |
| (app-step) status | done | active | pending | error | — | Overrides the status this step would otherwise derive from active-step. |
| (app-step) href | string | — | Makes the step a link back to that stage — only for a stage the user may revisit. |
| (app-step) description | string | — | A secondary line under the label. |
| (app-step) icon | string | — | An icon name shown in the circle in place of the number (a done/error step keeps its own glyph). |
| onStepClick | — | — | React-only — makes each step a button reporting its index for a JS-driven wizard. No Razor counterpart; use href for server-rendered navigation instead. |