---
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 (
<>