useWizard
useWizard(wizard) reads a wizard into a view for a multi-step screen. It subscribes the component to the wizard stores — steps, visibleSteps, currentId, currentIndex, currentStep, currentForm, visitedIds, completedIds, canGoBack, and canGoNext — and returns async handlers already bound to the nearest scope: next(), back(), goTo(id), complete(), and reset().
The navigation handlers next(), back(), goTo(id), and complete() return Promise<boolean> — true when the move happened, false when validation blocked it. reset() returns Promise<void>.
Make sure a scope is provided above the component — see the section overview for the shared ScopeProvider setup.
useWizardForm is an alias for useWizard; use whichever name reads better next to createWizardForm.
A wizard screen
The current step stores a form model, so the screen can choose a component by currentId and gate the Back and Next buttons on canGoBack / canGoNext.
import { useWizard } from "@virentia/forms-react";
function SignupWizardScreen() {
const wizard = useWizard(signupWizard);
return (
<>
{wizard.currentId === "account" ? <AccountStep /> : null}
{wizard.currentId === "billing" ? <BillingStep /> : null}
<footer>
<button
type="button"
disabled={!wizard.canGoBack}
onClick={() => void wizard.back()}
>
Back
</button>
<button
type="button"
disabled={!wizard.canGoNext}
onClick={() => void wizard.next()}
>
Next
</button>
</footer>
</>
);
}The buttons are disabled at the edges: !canGoBack on the first step, !canGoNext on the last. Clicking them calls wizard.back() and wizard.next(), both already scope-bound.
Validation gates Next
wizard.next() validates the current step form. If it is invalid, navigation does not happen, and the step fields show errors through the same components used by regular forms — the errors stay inside that step's form model.
async function goForward() {
const moved = await wizard.next();
if (!moved) {
// stayed on the current step; its fields now show validation errors
}
}This is why next() returns Promise<boolean>: true when the step was valid and the wizard advanced, false when it stayed put. goTo(id) and complete() follow the same contract — see validation for what runs inside step.form.validate(), and useForm for how a form surfaces those errors.
Reading a step form
Each step component reads its own form with useForm and renders its fields the same way any form does. The wizard only decides which step is current and whether navigation is allowed; the fields themselves are plain form fields.
import { useForm } from "@virentia/forms-react";
function AccountStep() {
const form = useForm(signupWizard.form.pick({ email: true, password: true }));
return (
<>
<TextInput label="Email" field={form.fields.email} />
<TextInput label="Password" field={form.fields.password} />
</>
);
}Because steps are form projections over the same field instances, the values a step edits flow straight into the root form and into wizard.read().
Contract
useWizard:
interface WizardView<Model extends Wizard> {
readonly wizard: Model;
readonly steps: unknown;
readonly visibleSteps: unknown;
readonly currentId: unknown;
readonly currentIndex: number;
readonly currentStep: unknown;
readonly currentForm: unknown;
readonly visitedIds: readonly unknown[];
readonly completedIds: readonly unknown[];
readonly canGoBack: boolean;
readonly canGoNext: boolean;
next(): Promise<boolean>;
back(): Promise<boolean>;
goTo(id: never): Promise<boolean>;
complete(): Promise<boolean>;
reset(): Promise<void>;
}useWizardForm is an alias for useWizard.
Next
- Wizard forms — the navigation model this hook renders.
- useForm — whole-form submit and backend errors inside a step.
- Validation — what runs inside
step.form.validate().