AppWizard
A multi-step flow with a progress header, one visible step at a time, and a sticky Back / Skip / Next / Finish footer.
<app-wizard><app-wizard-step label="…">…</app-wizard-step></app-wizard><app-wizard> is the whole flow, not just the progress header — AppStepper shows where the user is, but a wizard also owns which step's panel is visible and the footer that moves between them. Compose it with <app-wizard-step> children; each step's content is its panel.
The stepper header is built and driven the same way as AppStepper — steps / journey variant, horizontal / vertical orientation — so a form wizard and a standalone progress display never drift on look.
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 wizard above it.
Basic
Three steps, one Next/Back footer. The second step is optional, so its footer shows a Skip button while it is active.
Account step content.
Profile step content — this one can be skipped.
Review step content.
Show code
<app-wizard>
<app-wizard-step label="Account" description="Email & password">
<p>Account step content.</p>
</app-wizard-step>
<app-wizard-step label="Profile" description="Optional details" optional="true">
<p>Profile step content — this one can be skipped.</p>
</app-wizard-step>
<app-wizard-step label="Review" description="Confirm and submit">
<p>Review step content.</p>
</app-wizard-step>
</app-wizard>
Journey variant
Give the wizard variant="journey" for the wide bar style — a large dot beside a "STEP N" index and the step name — the same trade-off as AppStepper's journey bar: pick it when there is roughly 900px of width to show every step without truncating.
Account step content.
Profile step content — this one can be skipped.
Review step content.
Show code
<app-wizard variant="journey">…</app-wizard>
Icons variant
Give the wizard variant="icons" for large connected icon badges with a "STEP N" eyebrow above each title. Like every variant it defaults to a single brand-primary accent — solid-primary active badge, soft-primary done badge, primary rail (no multi-colour). Give every step an icon — a step without one falls back to its number. This example starts on step 2 (active="1") so the done-rail and the solid active badge are both visible. For any other colour, see Colours.
General information about the project.
Define the site and its structure.
Lay out the supply lines.
Configure the zone structure.
Run the analysis.
Review the result.
Show code
<app-wizard variant="icons" active="1">
<app-wizard-step label="General Info" icon="info">…</app-wizard-step>
<app-wizard-step label="Site & Structure" icon="building">…</app-wizard-step>
<app-wizard-step label="Supply Lines" icon="zap">…</app-wizard-step>
<app-wizard-step label="Zone Structure" icon="layout-grid">…</app-wizard-step>
<app-wizard-step label="Analysis" icon="chart-column">…</app-wizard-step>
<app-wizard-step label="Result" icon="shield-check">…</app-wizard-step>
</app-wizard>
Colours
Every wizard is a single brand-primary accent by default — colour is opt-in, and it lives here. Add tone="primary | success | warning | danger | info" to recolour the whole accent (active fill, done rail, ring, done tint) to a semantic ramp, on any variant. For any other colour, override the --wui-step-accent / --wui-step-soft / --wui-step-soft-fg CSS variables in a style or class; resize the badges with --wui-step-size (compact) / --wui-step-badge-size (icons). Error steps always stay red.
Primary — the default.
Second panel.
Third panel.
Success (green).
Second panel.
Third panel.
Danger (red).
Second panel.
Third panel.
Show code
<app-wizard>…</app-wizard> <!-- primary (default) --> <app-wizard tone="success">…</app-wizard> <app-wizard tone="danger">…</app-wizard>
--wui-step-* variables in a style (or product class). Here the icons wizard is recoloured to a custom purple.General information.
Site and structure.
Supply lines.
Analysis.
Result.
Show code
<app-wizard variant="icons"
style="--wui-step-accent: #7c3aed; --wui-step-soft: #efe7fd; --wui-step-soft-fg: #5b21b6;">
…
</app-wizard>
Validation — gating Next with beforeNext
The wizard gates advancing on a validation check. On Razor, hook the element's cancelable wui-wizard:beforechange event and call preventDefault() to block Next, or Finish on the last step (its event carries reason: "finish"). The blocked step turns red and the wizard fires wui-wizard:invalid. Step status is derived from position, so going back from the last step correctly returns the steps ahead to their pending (grey) state rather than leaving them marked done.
beforeNext prop; Razor wires the same gate through the element event. Here step 1 (Terms) is blocked until the box is ticked.You must accept the terms before continuing.
Enter your payment details.
Review and submit.
Show code
<app-wizard id="gated-wizard">
<app-wizard-step label="Terms">
<input type="checkbox" id="gated-terms" /> I accept the terms
</app-wizard-step>
<app-wizard-step label="Payment">…</app-wizard-step>
<app-wizard-step label="Confirm">…</app-wizard-step>
</app-wizard>
<script>
document.getElementById('gated-wizard')
.addEventListener('wui-wizard:beforechange', function (e) {
if (e.detail.index === 0 && !document.getElementById('gated-terms').checked) {
e.preventDefault(); // blocks Next; step turns red, wui-wizard:invalid fires
}
});
</script>
beforeNext property (the same one React sets from its prop) that can return a Promise — the wizard awaits it before advancing or flagging the step invalid.An async check (simulated 600ms request) must resolve true before Next advances.
Checking…
Enter your payment details.
Review and submit.
Show code
<app-wizard id="async-gated-wizard">…</app-wizard>
<script>
var wiz = document.getElementById('async-gated-wizard');
wiz.beforeNext = function (index) {
if (index !== 0) return true;
return new Promise(function (resolve) {
setTimeout(function () { resolve(termsChecked); }, 600);
});
};
</script>
Skip an optional step
A step marked optional shows a Skip button in the footer only while it is the active step — Skip is not a permanent extra button, it appears exactly where it applies and moves the wizard forward without requiring the panel's fields to validate.
wui-wizard:skip with the step's index.Account panel.
Profile panel — click Skip to move on without filling this in.
Review panel.
Show code
<app-wizard id="skip-wizard">
<app-wizard-step label="Account">…</app-wizard-step>
<app-wizard-step label="Profile" optional="true">…</app-wizard-step>
<app-wizard-step label="Review">…</app-wizard-step>
</app-wizard>
<script>
document.getElementById('skip-wizard')
.addEventListener('wui-wizard:skip', function (e) {
// e.detail.index = the skipped step
});
</script>
skippable on the wizard and every step (bar the last) shows a Skip button, without marking each one optional. Per-step optional still works on its own.Any step can be skipped — Skip shows here without optional.
Second panel — also skippable.
Last step — no Skip, just Finish.
Show code
<app-wizard skippable="true">
<app-wizard-step label="Account">…</app-wizard-step>
<app-wizard-step label="Profile">…</app-wizard-step>
<app-wizard-step label="Review">…</app-wizard-step>
</app-wizard>
Non-linear navigation
By default the stepper header only makes earlier (completed) steps clickable — forward movement is Next-only. non-linear="true" makes every step header clickable, so the user can jump straight to any step, forward or back.
Account panel — every step header is clickable, not only earlier ones.
Profile panel.
Review panel — jump straight here from the header without using Next.
Show code
<app-wizard non-linear="true" active="1">
<app-wizard-step label="Account">…</app-wizard-step>
<app-wizard-step label="Profile">…</app-wizard-step>
<app-wizard-step label="Review">…</app-wizard-step>
</app-wizard>
The Finish state
Pressing Finish on the last step fires wui-wizard:finish and moves the whole flow into its completed state: every step reads done (the connecting rail fills) and the active ring drops from the last step.
Set your email and password.
Tell us a little about yourself.
Review everything, then press Finish.
Show code
<app-wizard id="finish-wizard" active="2">…</app-wizard>
<script>
document.getElementById('finish-wizard')
.addEventListener('wui-wizard:finish', function () {
// every step now reads done
});
</script>
When to use
Use it when
- A task is genuinely split across several ordered screens and each one is a real step, not just a tab.
- You need the standard Back / Skip / Next / Finish footer wired up, not just a progress indicator.
- Some steps are optional and the user should be able to skip past them explicitly.
Reach for something else when
- It is one form on a single screen with grouped sections. → app-form-section + app-form-row + app-form-actions
- You only need to show progress — navigation lives elsewhere (a route, a parent component). → app-stepper
- The sections are alternative views the user switches between freely, not a sequence. → app-tabs
Every option
The whole surface of the component, one cell per value — the three header variants, every tone, both orientations, the forced step statuses, the standalone navigation flags, and custom footer labels.
variant — all three
variant="steps"
Account panel.
Profile panel.
Review panel.
variant="journey"
Account panel.
Profile panel.
Review panel.
variant="icons"
General Info panel.
Site & Structure panel.
Supply Lines panel.
tone — every preset, journey variant
tone="primary (default)"
Account panel.
Profile panel.
Review panel.
tone="primary"
Account panel.
Profile panel.
Review panel.
tone="success"
Account panel.
Profile panel.
Review panel.
tone="warning"
Account panel.
Profile panel.
Review panel.
tone="danger"
Account panel.
Profile panel.
Review panel.
tone="info"
Account panel.
Profile panel.
Review panel.
orientation
orientation="horizontal"
Account panel.
Profile panel.
Review panel.
orientation="vertical"
Account panel.
Profile panel.
Review panel.
step status — forced via a step's status
status="done"
Forced status panel.
Second panel.
status="active"
Forced status panel.
Second panel.
status="pending"
Forced status panel.
Second panel.
status="error"
Forced status panel.
Second panel.
standalone flags
skippable="true" — Skip on every non-last step
Account panel.
Profile panel.
Review panel.
non-linear="true" — every header step is clickable
Account panel.
Profile panel.
Review panel.
hide-stepper="true" — footer navigation only, no header
Account panel.
Profile panel.
Review panel.
disabled="true" — header and footer navigation both inert
Account panel.
Profile panel.
Review panel.
custom footer labels
back-label / next-label / finish-label
Account panel.
Profile panel.
Review panel.
skip-label — shown on the optional step
Account panel.
Profile panel — click "Later" to skip.
Review panel.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| active | int | 0 | Initial step index. Only emitted on the element when greater than 0. |
| variant | steps | journey | icons | steps | The stepper header style — compact circles, a wide journey bar, or large connected icon badges with a "STEP N" eyebrow. |
| tone | primary | success | warning | danger | info | — | Recolour the whole stepper accent to a semantic ramp. Unset defaults every variant to brand primary. For any other colour, override the --wui-step-accent / --wui-step-soft / --wui-step-soft-fg CSS variables (and --wui-step-size / --wui-step-badge-size for sizing). |
| skippable | bool | false | Show a Skip button on every step (bar the last) without marking each optional. Per-step optional still works on its own. |
| orientation | horizontal | vertical | horizontal | Vertical stacks the header down a side rail — for a narrow column or drawer. |
| non-linear | bool | false | Allow jumping to any step, not only completed ones. |
| hide-stepper | bool | false | Hide the progress header — footer navigation only. |
| disabled | bool | false | Disable all navigation (header and footer). |
| label | string | Progress | Accessible name for the stepper. |
| back-label | string | Back | Footer's previous-step button label. |
| next-label | string | Next | Footer's advance button label (hidden on the last step in favour of Finish). |
| skip-label | string | Skip | Footer's skip button label — shown only while an optional step is active. |
| finish-label | string | Finish | Footer's submit button label, shown on the last step. |
<app-wizard-step> takes label, description (secondary line under the label), optional (shows Skip while active), icon (a glyph in the circle in place of the number) and status (done | active | pending | error — force a step's status instead of deriving it from the current step). Its child content is the step's panel.