Multi-step form with typed step ids, per-step validation gates, progress, and persisted drafts.
|
|
| Package |
@vizejs/ui/form-wizard |
| Maturity |
stable |
| Own the source |
vize lib pull form-wizard |
| Requires |
context, controllable-state, id |
| Aliases |
multi-step form, wizard, checkout steps, onboarding flow |
| Covers |
WAI-ARIA aria-current=step, Chakra Steps, Ark UI Steps |
Usage
import { FormWizard, FormWizardStep, FormWizardNext, FormWizardBack, FormWizardProgress } from "@vizejs/ui/form-wizard";
Or copy the source into your project with vize lib pull form-wizard (see Source Distribution).
API
Source: src/families/form/form-wizard/form-wizard.vue
Props
| Prop |
Type |
Default |
Description |
steps (required) |
readonly StepId[] |
required |
Step ids in order; their literal union types every step-related API. |
modelValue |
StepId |
undefined |
Controlled current step. undefined selects uncontrolled behavior. |
defaultValue |
StepId |
steps[0] |
Initial uncontrolled step. |
validate |
FormWizardValidate<StepId> |
undefined |
Validation gate run before leaving a step forward and before completing. |
linear |
boolean |
true |
Only allow jumping forward to visited steps (or the next one). |
draft |
FormWizardDraftStore<StepId> |
undefined |
Persisted draft store for the current and visited steps. |
focusOnChange |
boolean |
true |
Move focus to the newly current step panel after a user transition. |
id |
string | null |
undefined |
Base id for panels (<id>-<step>). null and undefined select a deterministic fallback. |
ariaLabel |
string |
undefined |
Accessible name of the wizard region. |
ariaLabelledby |
string |
undefined |
Ids that label the wizard region. |
Events
| Event |
Payload |
Description |
update:modelValue |
[step: StepId] |
Fired when the current step requests a change. |
change |
[step: StepId, previous: StepId, direction: FormWizardDirection] |
Fired after the current step changes, with the previous step and direction. |
blocked |
[step: StepId, target: StepId] |
Fired when a validation gate keeps the wizard on a step. |
complete |
[] |
Fired when the last step passes its gate. |
Slots
| Slot |
Slot props |
Description |
default |
FormWizardSlotState<StepId> |
Renders step panels, navigation, and progress with the typed wizard state. |
Exposed
| Member |
Type |
Description |
steps |
readonly StepId[] |
Every step id, in order. |
current |
StepId |
Current step. |
index |
number |
Zero-based index of the current step. |
count |
number |
Number of steps. |
progress |
number |
Completed fraction from 0 to 1 (index / (count - 1), 1 for a single step). |
visited |
readonly StepId[] |
Steps reached so far, in step order. |
isFirst |
boolean |
Whether the current step is the first. |
isLast |
boolean |
Whether the current step is the last. |
validating |
boolean |
Whether a validation gate is running. |
completed |
boolean |
Whether the last step passed its gate and complete was emitted. |
state |
FormWizardState |
Stable state token. |
next |
() => Promise<boolean> |
Validate the current step, then advance (or complete on the last step). |
back |
() => boolean |
Go to the previous step without validation. |
goTo |
(step: StepId) => Promise<boolean> |
Go to a step; moving forward validates every step in between. |
reset |
() => void |
Return to the first step, forget visited steps, and clear the draft. |
root |
— |
|
Source: src/families/form/form-wizard/form-wizard-step.vue
Props
| Prop |
Type |
Default |
Description |
step (required) |
string |
required |
Step id this panel belongs to; must be one of the wizard steps. |
label |
string |
undefined |
Accessible name of the step panel, for example its heading text. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly active: boolean; readonly index: number } |
Step contents; rendered for every step so field state survives navigation. |
Source: src/families/form/form-wizard/form-wizard-next.vue
Slots
| Slot |
Slot props |
Description |
default |
{ readonly isLast: boolean; readonly validating: boolean } |
Button contents; isLast lets consumers switch between "Next" and "Finish". |
Source: src/families/form/form-wizard/form-wizard-back.vue
Slots
| Slot |
Slot props |
Description |
default |
{ readonly isFirst: boolean } |
Button contents. |
Source: src/families/form/form-wizard/form-wizard-progress.vue
Props
| Prop |
Type |
Default |
Description |
formatValueText |
(step: number, count: number) => string |
(step, count) => Step ${step} of ${count} |
Builds the announced value text from the 1-based step number and total. |
ariaLabel |
string |
"Progress" |
Accessible name of the progress bar. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly step: number; readonly count: number; readonly progress: number; } |
Optional fallback contents rendered inside the native progress element. |
Behavior
Normative state x input -> outcome table for form-wizard.vue,
form-wizard-step.vue, form-wizard-next.vue, form-wizard-back.vue, and
form-wizard-progress.vue (@vizejs/ui/form-wizard). steps infers the step-id
union used by v-model, gates, events, and the expose API. Every row is proven
by the named test in form-wizard.test.ts or form-wizard-ssr.test.ts;
inference is pinned in form-wizard.types.test-d.ts.
| # |
State |
Input |
Outcome |
Proven by |
| W1 |
first step |
render |
labelled role="group"; every panel renders (hidden unless current, aria-current="step"); Back disabled; native progress "Step 1 of 3" |
renders every step panel with only the current one visible |
| W2 |
any |
Next / Back |
Next advances (or emits complete on the last step), Back returns; change(step, previous, direction) fires and focus moves to the new panel |
next and back move between steps, focus the panel, and complete on the last step |
| W3 |
gated |
Next |
the gate receives { step, target, signal }; while pending the root is aria-busy and Next is disabled; false keeps the step and emits blocked; Back never validates |
validation gates block forward moves and report the blocked step |
| W4 |
linear |
goTo |
backward jumps are free; forward jumps need visited targets (unless linear=false) and validate every step in between |
goTo jumps back freely, forward only through visited steps, validating in between |
| W5 |
draft store |
mount / change / complete / reset |
the draft loads after mount (unknown steps ignored), saves { step, visited } after each change, and clears on completion and reset |
drafts restore after mount, save every change, and clear on completion or reset |
| W6 |
controlled |
Next |
emits the request; the rendered step follows modelValue |
controlled steps win until the parent accepts them |
| W7 |
invalid setup |
empty steps / missing root |
throws VIZE_UI_FORM_WIZARD_STEPS or VIZE_UI_CONTEXT_MISSING: FormWizard |
rejects empty step lists and parts outside a FormWizard |
| W8 |
SSR / hydration |
isolated requests |
the server renders the default step; drafts apply only after hydration, so markup matches and no mismatch is reported |
renders the default step on the server and applies drafts only after hydration |
Public extension contract
| Surface |
Contract |
| Parts |
root, step (panel), next, back, progress. |
| Data attributes |
root data-state (in-progress/validating/complete) and data-step; panel data-state (active/visited/upcoming). |
| CSS properties |
--vize-form-wizard-progress on the progress element (0%–100%). |
| Integration |
Gate each step with useForm validation (for example validate: () => form.validate().then((r) => r.valid)). |
The subpath is tree-shakable and ships no CSS; those package contracts are
pinned by distribution.test.ts, check:size, and check:tree-shaking.