--- name: stepper-command-dialog description: Step-by-step guidance for building a multi-step wizard dialog (StepperCommandDialog) in a Cratis Arc application. Use whenever a command requires gathering information across multiple steps, implementing a wizard flow, breaking a complex form into named stages, or using StepperCommandDialog, StepperPanel, validateOnInit, or wizard-style navigation. --- # StepperCommandDialog — Wizard Dialogs `StepperCommandDialog` organizes a single command form across multiple named steps. Users navigate with **Previous** and **Next** buttons; **Submit** only appears on the last step when every field across all steps is valid. Use this instead of `CommandDialog` when: - The form has too many fields to show at once - Fields can be grouped into logical stages (e.g. "Contact Info → Project Details → Summary") - You want guided, linear input with per-step validation feedback - The operation feels like a wizard or an onboarding flow --- ## Step 1 — Define the command A single command collects all fields across all steps. Each step contributes properties to the same command instance. ```csharp // Projects/CreateProject/CreateProject.cs — the slice file [Command] public record CreateProject(ProjectName Name, EmailAddress Email, Description Description, Money Budget) { public ProjectCreated Handle() => new(Name, Email, Description, Budget); } ``` Run a Debug `dotnet build` to generate the `CreateProject` TypeScript proxy before importing it. --- ## Step 2 — Build the dialog component ```tsx import { StepperCommandDialog } from '@cratis/components/CommandDialog'; import { StepperPanel } from '@cratis/components/CommandDialog'; import { InputTextField, TextAreaField, NumberField } from '@cratis/components/CommandForm/fields'; import { DialogResult, useDialogContext } from '@cratis/arc.react/dialogs'; import { CreateProject } from '../api/Projects/CreateProject'; const CreateProjectDialog = () => { const { closeDialog } = useDialogContext(); return ( command={CreateProject} title="Create New Project" okLabel="Create" onConfirm={() => closeDialog(DialogResult.Ok)} onCancel={() => closeDialog(DialogResult.Cancelled)} > value={c => c.email} title="Contact Email" placeholder="Enter contact email" type="email" /> value={c => c.name} title="Project Name" placeholder="Enter project name" /> value={c => c.description} title="Description" placeholder="Describe the project" rows={4} /> value={c => c.budget} title="Budget" placeholder="Enter budget" /> ); }; ``` **Rules:** - Each `StepperPanel` takes a `header` string — this is the step label shown in the wizard navigation bar - All `CommandForm` fields inside any `StepperPanel` are bound to the **same** command instance - Fields map to command properties via the `value={c => c.propertyName}` accessor - The `Next` button is disabled while the current step has validation errors - `Submit` only appears on the **last** step when all fields (across all steps) are valid --- ## Step 3 — Wire the dialog to a parent component ```tsx import { useDialog } from '@cratis/arc.react/dialogs'; import { Button } from 'primereact/button'; export const ProjectsPage = () => { const [CreateProjectDialogWrapper, showCreateProject] = useDialog(CreateProjectDialog); return ( <>