# Pattern: Wizard (Multi-Step Form)

A multi-step form pattern using the `Stepper` component to guide users through a sequential process with validation at each step.

---

## When to Use

Use the Wizard pattern when:

- A form has more than 4–5 fields and benefits from being broken into logical sections
- Each step has its own validation before proceeding
- The user needs to review a summary before final submission
- The process has a clear linear sequence (e.g., onboarding, checkout, configuration)

---

## Components Used

- [`Stepper`](../components/stepper.md) — step indicator and navigation
- [`Card`](../components/card.md) — content container for each step
- [`Button`](../components/button.md) — Next, Back, and Submit actions
- [`Form`](../components/form.md) + [`Input`](../components/input.md) — form fields with validation
- [`PageHeader`](../components/page-header.md) — page title and breadcrumb

---

## Basic Structure

```tsx
import { useState } from 'react';
import { Stepper } from 'xertica-ui/ui';
import { Button } from 'xertica-ui/ui';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from 'xertica-ui/ui';

const STEPS = [
  { id: 'info', label: 'Informações Básicas' },
  { id: 'address', label: 'Endereço' },
  { id: 'review', label: 'Revisão' },
];

export function WizardExample() {
  const [currentStep, setCurrentStep] = useState(0);
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    street: '',
    city: '',
  });

  const isLastStep = currentStep === STEPS.length - 1;

  const handleNext = () => {
    if (!isLastStep) setCurrentStep(s => s + 1);
    else handleSubmit();
  };

  const handleBack = () => {
    if (currentStep > 0) setCurrentStep(s => s - 1);
  };

  const handleSubmit = () => {
    console.log('Submitted:', formData);
  };

  return (
    <div className="max-w-2xl mx-auto p-6 space-y-6">
      <Stepper steps={STEPS} currentStep={currentStep} onStepClick={setCurrentStep} />

      <Card>
        <CardHeader>
          <CardTitle>{STEPS[currentStep].label}</CardTitle>
        </CardHeader>

        <CardContent>
          {currentStep === 0 && <StepBasicInfo data={formData} onChange={setFormData} />}
          {currentStep === 1 && <StepAddress data={formData} onChange={setFormData} />}
          {currentStep === 2 && <StepReview data={formData} />}
        </CardContent>

        <CardFooter className="flex justify-between">
          <Button variant="outline" onClick={handleBack} disabled={currentStep === 0}>
            Voltar
          </Button>
          <Button onClick={handleNext}>{isLastStep ? 'Confirmar' : 'Próximo'}</Button>
        </CardFooter>
      </Card>
    </div>
  );
}
```

---

## Step Components

Each step is a focused form section:

```tsx
function StepBasicInfo({ data, onChange }) {
  return (
    <div className="space-y-4">
      <div className="space-y-2">
        <Label htmlFor="name">Nome completo</Label>
        <Input
          id="name"
          value={data.name}
          onChange={e => onChange(prev => ({ ...prev, name: e.target.value }))}
          placeholder="João Silva"
        />
      </div>
      <div className="space-y-2">
        <Label htmlFor="email">E-mail</Label>
        <Input
          id="email"
          type="email"
          value={data.email}
          onChange={e => onChange(prev => ({ ...prev, email: e.target.value }))}
          placeholder="joao@empresa.com"
        />
      </div>
    </div>
  );
}

function StepReview({ data }) {
  return (
    <div className="space-y-3">
      <div className="flex justify-between py-2 border-b border-border">
        <span className="text-muted-foreground">Nome</span>
        <span className="font-medium">{data.name}</span>
      </div>
      <div className="flex justify-between py-2 border-b border-border">
        <span className="text-muted-foreground">E-mail</span>
        <span className="font-medium">{data.email}</span>
      </div>
      <div className="flex justify-between py-2 border-b border-border">
        <span className="text-muted-foreground">Endereço</span>
        <span className="font-medium">
          {data.street}, {data.city}
        </span>
      </div>
    </div>
  );
}
```

---

## With React Hook Form Validation

For production forms, integrate `react-hook-form` with per-step validation:

```tsx
import { useForm } from 'react-hook-form';
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from 'xertica-ui/ui';

function StepBasicInfoValidated({ onValid }) {
  const form = useForm({
    defaultValues: { name: '', email: '' },
  });

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onValid)} className="space-y-4">
        <FormField
          control={form.control}
          name="name"
          rules={{ required: 'Nome é obrigatório' }}
          render={({ field }) => (
            <FormItem>
              <FormLabel>Nome</FormLabel>
              <FormControl>
                <Input {...field} placeholder="João Silva" />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Próximo</Button>
      </form>
    </Form>
  );
}
```

---

## Progress Persistence

For long wizards, persist progress in `localStorage` or a URL query parameter:

```tsx
// Save step to URL
const [searchParams, setSearchParams] = useSearchParams();
const currentStep = parseInt(searchParams.get('step') || '0');

const handleNext = () => {
  setSearchParams({ step: String(currentStep + 1) });
};
```

---

## AI Rules

> [!IMPORTANT]
>
> - **Use `Stepper` for the indicator**: Never build a custom step indicator with raw `div` elements. The `Stepper` component handles accessibility, active state, and completed state automatically.
> - **One `Card` per step**: Each step's content should be inside a single `Card`. Do not render multiple cards or use `Tabs` as a substitute for `Stepper`.
> - **Validate before advancing**: Always validate the current step's fields before calling `setCurrentStep(s => s + 1)`. Use `react-hook-form`'s `trigger()` method for partial validation.
> - **Review step is read-only**: The final review step should display a summary of all collected data. It must not contain editable fields.
> - **Back button is never disabled on step > 0**: Users must always be able to go back. Only disable the Back button on the first step.
