VisorVisor
Patterns

Wizard Flow

A multi-step guided flow with per-step validation, progress tracking, and a linear navigation structure for complex data collection.

Preview

New project

Create a project

Walk through a few steps to spin up a fresh project.

Basic info

Name and description

Select category

Pick a category and visibility

Configure

Starter template and notes

Review

Confirm and submit

When to Use

  • Onboarding flows, setup wizards, or checkout sequences
  • When a single long form would overwhelm the user — break into logical steps
  • Flows where earlier steps gate or inform later steps

Components Used

Structure

<div className="wizard-layout">
  <Progress value={(currentStep / totalSteps) * 100} aria-label="Setup progress" />

  <Stepper currentStep={currentStep} steps={steps}>
    <StepperItem step={1} label="Account" />
    <StepperItem step={2} label="Profile" />
    <StepperItem step={3} label="Preferences" />
    <StepperItem step={4} label="Review" />
  </Stepper>

  <Separator />

  <div className="wizard-content">
    {currentStep === 1 && (
      <div>
        <Field label="Email" required>
          <Input type="email" value={form.email} onChange={handleChange("email")} />
        </Field>
        <Field label="Password" required>
          <Input type="password" value={form.password} onChange={handleChange("password")} />
        </Field>
      </div>
    )}

    {currentStep === 2 && (
      <div>
        <Field label="Full Name" required>
          <Input value={form.name} onChange={handleChange("name")} />
        </Field>
        <Field label="Job Title">
          <Input value={form.title} onChange={handleChange("title")} />
        </Field>
      </div>
    )}

    {stepError && (
      <Alert variant="destructive">
        <AlertDescription>{stepError}</AlertDescription>
      </Alert>
    )}
  </div>

  <div className="wizard-actions">
    <Button variant="ghost" onClick={handleBack} disabled={currentStep === 1}>
      Back
    </Button>
    <Button onClick={handleNext} loading={validating}>
      {currentStep === totalSteps ? "Finish" : "Next"}
    </Button>
  </div>
</div>

Notes

  • Validate each step before advancing — show the Alert for step-level errors, not field-level.
  • Progress bar gives a continuous sense of completion; Stepper gives discrete step identity.
  • Persist wizard state in component state or URL search params to survive accidental back navigation.
  • Disable the Back button on the first step rather than hiding it to preserve layout stability.