Skip to content

Wizard

Purpose

The Wizard component provides a complete multi-step form experience:

  • Step-by-step navigation with progress indicator
  • Form state management across steps
  • Per-step validation
  • Consistent header, content, and footer layout

When to use

Use Wizard for:

  • Multi-step onboarding flows
  • Complex form wizards (checkout, registration)
  • Guided setup processes
  • Any flow that benefits from breaking into discrete steps

Basic usage

tsx
import { Wizard } from '@/shared/ui/components/wizard'

type FormData = {
  name: string
  email: string
  plan: string
}

const steps = [
  {
    id: 'personal',
    title: 'Personal Info',
    description: 'Enter your details',
    render: (values, setValues, errors) => (
      <div>
        <input
          value={values.name}
          onChange={(e) => setValues({ name: e.target.value })}
          placeholder="Name"
        />
        <input
          value={values.email}
          onChange={(e) => setValues({ email: e.target.value })}
          placeholder="Email"
        />
        {errors.map((err) => <p key={err} className="text-red-500">{err}</p>)}
      </div>
    ),
  },
  {
    id: 'plan',
    title: 'Select Plan',
    render: (values, setValues) => (
      <select
        value={values.plan}
        onChange={(e) => setValues({ plan: e.target.value })}
      >
        <option value="free">Free</option>
        <option value="pro">Pro</option>
      </select>
    ),
  },
]

export function OnboardingWizard() {
  return (
    <Wizard
      steps={steps}
      initialValues={{ name: '', email: '', plan: 'free' }}
      onFinish={(values) => console.log('Complete:', values)}
      onCancel={() => console.log('Cancelled')}
      validateStep={(stepIndex, values) => {
        if (stepIndex === 0 && !values.name) {
          return ['Name is required']
        }
        return null
      }}
    />
  )
}

Props

WizardProps

PropTypeRequiredDescription
stepsWizardStep<T>[]YesArray of step configurations
initialValuesTYesInitial form values
onFinish(values: T) => voidYesCalled when wizard completes
onCancel() => voidNoCalled when user cancels
validateStep(stepIndex: number, values: T) => string[] | nullNoPer-step validation
classNamestringNoAdditional CSS class

WizardStep

PropertyTypeRequiredDescription
idstringYesUnique step identifier
titlestringYesStep title shown in header
descriptionstringNoOptional step description
render(values, setValues, errors) => ReactNodeYesStep content renderer

Compound components

The Wizard exposes sub-components for custom layouts:

tsx
<Wizard steps={steps} initialValues={initial} onFinish={handleFinish}>
  <Wizard.Header className="custom-header" />
  <Wizard.Content className="custom-content" />
  <Wizard.Footer 
    cancelLabel="Exit"
    previousLabel="Back"
    nextLabel="Continue"
    finishLabel="Complete"
    showCancel={true}
  />
</Wizard>

Notes

  • The wizard manages its own step state internally
  • Validation errors are passed to the render function for display
  • Navigation is blocked if validation fails
  • Use validateStep to implement per-step validation logic