Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Multi-step form wizard with per-step validation, conditional steps, and progress tracking. Add data-wizard to a form to split fieldsets into navigable steps.
The data-wizard attribute transforms a standard form with multiple fieldsets into a multi-step wizard. Each <fieldset data-wizard-step> becomes a navigable step with per-step validation, conditional visibility, and progress tracking. This page is an attribute-focused API reference.
For full walkthroughs and pattern examples, see the Wizard Pattern page.
<form data-wizard> <fieldset data-wizard-step> <legend>Account</legend> <input name="email" type="email" required> </fieldset> <fieldset data-wizard-step> <legend>Profile</legend> <input name="name" required> </fieldset> <nav data-wizard-nav> <button type="button" data-wizard-prev>Back</button> <button type="button" data-wizard-next>Next</button> <button type="submit">Submit</button> </nav></form>
Add data-wizard to a <form> containing multiple <fieldset data-wizard-step> elements. The init script:
[data-wizard-step] fieldsets within the formdata-wizard-active / data-wizard-hiddendata-wizard-prev and data-wizard-next buttons for navigationdata-wizard-if conditions to skip inapplicable steps<progress> and external nav.steps if connecteddata-wizard-enhanced on the form to prevent double-bindingThe submit button is only enabled on the final step. On earlier steps, clicking Next validates the current step before proceeding.
| Attribute | Element | Description |
|---|---|---|
data-wizard |
<form> |
Enables wizard behavior on the form. |
data-wizard-step |
<fieldset> |
Marks a fieldset as a wizard step. |
data-wizard-progress |
<progress> |
Auto-updated progress bar. Value reflects current step / total steps. |
data-wizard-nav |
<nav> |
Container for navigation buttons. The wizard manages button visibility. |
data-wizard-prev |
<button> |
Go to previous step. Hidden on the first step. |
data-wizard-next |
<button> |
Go to next step (validates current step first). Hidden on the last step. |
data-wizard-if |
<fieldset> |
Conditional step. Formats: "name:value", "name:!value", "name", "!name". |
data-wizard-optional |
<fieldset> |
Step can be skipped without validation. |
data-wizard-summary |
<fieldset> |
Marks a step as a review/summary step. Child elements with data-wizard-field="name" are populated with the named field's value. If no data-wizard-field children exist, a <dl> is auto-generated from all non-empty form values. |
data-wizard-field |
any element | Inside a summary step, displays the value of the named form field. Element's textContent is replaced with the field value. |
data-wizard-steps |
<form> |
CSS selector for an external nav.steps element to sync as progress nav. |
data-wizard-history |
<form> |
Opt-in URL hash synchronization. Syncs current step to #step=N and restores on page load. |
data-wizard-persist |
<form> |
Save/restore form data and step across reloads. Values: "session" (sessionStorage) or "local" (localStorage). Requires id on the form. |
data-wizard-validate |
<form> |
Validation mode. "step" (default) validates before advancing. "none" allows free navigation; validation occurs only on submit. |
data-wizard-enhanced |
<form> |
Auto-set after init. Do not set manually. |
data-wizard-active / data-wizard-hidden |
<fieldset> |
Auto-set to mark the visible step and hide inactive steps. |
data-wizard-current / data-wizard-total |
<form> |
Auto-set with current step index (1-based) and total visible steps. |
data-wizard-last |
<form> |
Auto-set when on the final step. |
Add a <progress data-wizard-progress> element inside the form. The wizard sets its value and max attributes automatically as the user navigates.
<form data-wizard> <progress data-wizard-progress></progress> <!-- steps... --></form>
Use data-wizard-if on a fieldset to make it conditional. The step is only included in the wizard flow when the condition matches. Skipped steps do not count toward the total and their validation is bypassed. Four condition formats are supported:
name:value — show when field equals valuename:!value — show when field does not equal valuename — show when field has any truthy value!name — show when field is empty or uncheckedname:a && other:b — AND: show when all conditions are truename:a || name:b — OR: show when any condition is trueAND (&&) has higher precedence than OR (||), so a:x && b:y || c:z means "(a equals x AND b equals y) OR (c equals z)".
<fieldset data-wizard-step data-wizard-if="account-type:business"> <legend>Business Details</legend> <!-- Only shown when account-type field = business --></fieldset>
Use data-wizard-steps on the form with a CSS selector pointing to an external nav.steps element. The wizard synchronizes the nav's list items with the current step, applying aria-current="step" to the active item. The nav can be placed anywhere on the page.
<form data-wizard data-wizard-steps="#progress-nav"> <!-- steps... --></form> <nav class="steps" id="progress-nav" aria-label="Progress"> <ol> <li>Account</li> <li>Profile</li> <li>Review</li> </ol></nav>
If the nav.steps ol is empty (no <li> children), the wizard auto-populates it from the <legend> text of each step fieldset. This saves you from duplicating step names.
If no [data-wizard-nav] element is found in the form, the wizard automatically injects a navigation bar with Back, Next, and Submit buttons. This lets you create a minimal wizard with just steps:
<form data-wizard> <fieldset data-wizard-step><legend>Step 1</legend>...</fieldset> <fieldset data-wizard-step><legend>Step 2</legend>...</fieldset> <!-- nav is auto-injected with Back / Next / Submit --></form>
Add data-wizard-summary to a step fieldset to make it a review step. There are two modes:
Place elements with data-wizard-field="fieldName" inside the summary step. Their text content is replaced with the corresponding field value when the step becomes active.
<fieldset data-wizard-step data-wizard-summary> <legend>Review</legend> <dl> <dt>Email</dt> <dd data-wizard-field="email"></dd> <dt>Name</dt> <dd data-wizard-field="fullname"></dd> </dl></fieldset>
If no data-wizard-field elements are found, a <dl> is auto-generated from all non-empty fields across visible steps, using labels as terms and field values as definitions.
<fieldset data-wizard-step data-wizard-summary> <legend>Review</legend> <!-- dl auto-generated from all form field values --></fieldset>
| Event | Detail | Description |
|---|---|---|
wizard:step-change |
{ from, to } |
Fired on step navigation. Indices are 0-based. |
wizard:complete |
— | Fired when the form is submitted from the final step. |
wizard:reset |
— | Fired when the wizard is reset to the first step. |
const form = document.querySelector('[data-wizard]'); form.addEventListener('wizard:step-change', (e) => { console.log('Moved from step', e.detail.from, 'to', e.detail.to);}); form.addEventListener('wizard:complete', () => { console.log('Wizard submitted');});
The wizard adds navigation methods directly to the form element:
form.wizardNext() — advance to next step (validates current step first)form.wizardPrev() — go back to previous step (no validation)form.wizardGoTo(index) — jump to step by 0-based indexform.wizardReset() — reset to first step and clear progressconst form = document.querySelector('[data-wizard]'); form.wizardNext(); // Go to next step (validates first)form.wizardPrev(); // Go to previous stepform.wizardGoTo(2); // Jump to step index 2form.wizardReset(); // Reset to first step/code-block </section> <section> <h2>Styling</h2> <p>Step visibility is controlled via <code>data-wizard-active</code> and <code>data-wizard-hidden</code> attributes. Nav buttons are automatically shown or hidden based on step position.</p> <code-block language="css" show-lines label="Wizard CSS selectors" data-escape>/* Active step */[data-wizard-step][data-wizard-active] { display: block;} /* Hidden steps */[data-wizard-step][data-wizard-hidden] { display: none;} /* Progress bar */[data-wizard] progress[data-wizard-progress] { width: 100%;}
All behavior is gated on data-wizard-enhanced. Without JavaScript, all fieldsets are visible and the form submits normally — progressive enhancement.
nav.steps uses aria-current="step" on the active step<progress> element provides a native accessible progress indicatorWizard Pattern — full walkthroughs, layout examples, and step-by-step tutorials.