Form Wire
Guides

Wizard (Multi-Step Forms)

Break forms into steps with per-step validation

Form Wire has built-in multi-step wizard support. Each step validates its own fields before advancing.

Basic Wizard

const Wizard = createFormWire(
  z.object({
    firstName: z.string().min(1),
    lastName: z.string().min(1),
    email: z.email(),
    company: z.string().min(1),
  }),
  { /* field config */ }
);

export function MyWizard() {
  return (
    <Wizard.Wizard action={submit}>
      <Wizard.Step title="Identity">
        <Wizard.Field name="firstName" />
        <Wizard.Field name="lastName" />
      </Wizard.Step>
      <Wizard.Step title="Contact">
        <Wizard.Field name="email" />
        <Wizard.Field name="company" />
      </Wizard.Step>
    </Wizard.Wizard>
  );
}

How It Works

  • Each <Step> declares which fields belong to it
  • The wizard renders one step at a time with Next/Previous buttons
  • Clicking "Next" validates only the current step's fields
  • The final step shows a "Submit" button
  • Server errors route back to the step that owns the failing field

Step Titles and Labels

<Wizard.Wizard
  action={submit}
  nextLabel="Continue"
  previousLabel="Go back"
  submitLabel="Send"
>

Layout Within Steps

Use Row for horizontal layouts:

import { Row } from "@form-wire/react";

<Wizard.Step title="Identity">
  <Row columns={2}>
    <Wizard.Field name="firstName" />
    <Wizard.Field name="lastName" />
  </Row>
</Wizard.Step>

Conditional Steps

Fields inside wizard steps support <When> just like regular forms:

<Wizard.Step title="Contact">
  <Wizard.Field name="email" />
  <Wizard.When field="accountType" equals="business">
    <Wizard.Field name="company" />
  </Wizard.When>
</Wizard.Step>

Hidden conditional fields are not validated when advancing steps.

Auto-Appended Fields

If a visible field isn't assigned to any step, it's automatically appended to the last step. This prevents fields from being silently dropped.

On this page