Skip to content

StepperCommandDialog

The StepperCommandDialog component provides a multi-step wizard dialog interface for executing commands, built on top of CommandStepper and the PrimeReact Stepper.

StepperCommandDialog organizes a command form across multiple steps, guiding users through a wizard-like workflow. All steps gather into the same underlying command — the Submit button only appears when all fields across every step are valid and the user has reached the last step.

  • Multi-step wizard navigation with Previous and Next buttons
  • All steps share a single command form — one command is submitted at the end
  • Submit button only appears on the last step when all fields are valid
  • Previous button hidden on the first step; Next button hidden on the last step
  • Cancel via the X button in the upper-right corner — no footer Cancel button
  • Step number circles change color to indicate validation state (red = errors, green = visited and valid)
  • Non-active steps are visually dimmed to keep focus on the current step
  • Busy state management during command execution
  • All PrimeReact Stepper customization props available directly (orientation, headerPosition, pt, etc.)
  • Supports any CommandForm field types inside each StepperPanel
  • Full integration with Cratis Arc command system
import { StepperCommandDialog } from '@cratis/components/CommandDialog';
import { StepperPanel } from 'primereact/stepperpanel';
import { InputTextField, TextAreaField, NumberField } from '@cratis/components/CommandForm/fields';
import { CommandResult } from '@cratis/arc/commands';
import { DialogResult, useDialog, useDialogContext } from '@cratis/arc.react/dialogs';
type CreateProjectResponse = {
projectId: string;
};
const CreateProjectDialog = () => {
const { closeDialog } = useDialogContext<CommandResult<CreateProjectResponse>>();
return (
<StepperCommandDialog<CreateProject, CreateProjectResponse>
command={CreateProject}
title="Create New Project"
okLabel="Create"
onSuccess={(response) => {
console.log('Project created:', response.projectId);
closeDialog(DialogResult.Ok);
}}
onValidationFailure={(errors) => {
console.error('Validation failed:', errors);
}}
onCancel={() => closeDialog(DialogResult.Cancelled)}
>
<StepperPanel header="Basic Info">
<InputTextField<CreateProject> value={c => c.name} title="Project Name" />
<InputTextField<CreateProject> value={c => c.email} title="Contact Email" type="email" />
</StepperPanel>
<StepperPanel header="Details">
<TextAreaField<CreateProject> value={c => c.description} title="Description" rows={4} />
<NumberField<CreateProject> value={c => c.budget} title="Budget" />
</StepperPanel>
</StepperCommandDialog>
);
};
function MyComponent() {
const [CreateProjectDialogWrapper, showCreateProjectDialog] = useDialog(CreateProjectDialog);
return (
<>
<button onClick={() => showCreateProjectDialog()}>Create Project</button>
<CreateProjectDialogWrapper />
</>
);
}
  • command: Constructor for the command type
  • title: Dialog title text
  • children: StepperPanel elements defining each step
  • visible: Boolean controlling dialog visibility (defaults to true)
  • initialValues: Initial values for the command form
  • currentValues: Current values to populate the form
  • onSuccess: Callback invoked on successful command execution with the typed response
  • onFailed: Callback invoked when command execution fails with the full CommandResult<TResponse>
  • onException: Callback invoked when the command throws an exception with error messages and stack trace
  • onUnauthorized: Callback invoked when authorization fails
  • onValidationFailure: Callback invoked on validation errors with the validation results
  • onConfirm: Confirm callback — called only after successful command execution
  • onCancel: Cancel callback — invoked when the X button is clicked
  • onClose: Fallback close callback
  • okLabel: Label for the submit button shown on the last step when valid (default: 'Submit')
  • nextLabel: Label for the next step button (default: 'Next')
  • previousLabel: Label for the previous step button (default: 'Previous')
  • isValid: Additional validity gate combined with command form validity
  • width: Dialog width (default: '600px')
  • resizable: Whether the dialog can be resized
  • style: Custom CSS styles
  • contentStyle: Custom CSS styles for the dialog content area
  • onFieldValidate: Custom validation function for fields
  • onFieldChange: Callback when field values change
  • onBeforeExecute: Transform command values before execution

All PrimeReact Stepper customization props are available directly:

  • orientation: 'horizontal' (default) or 'vertical'
  • headerPosition: 'top', 'right', 'bottom', or 'left'
  • linear: Whether steps must be completed in order (default: true)
  • onChangeStep: Callback when the active step changes
  • start: Custom content rendered before the stepper navigation
  • end: Custom content rendered after the stepper navigation
  • pt: PrimeReact PassThrough options for deep DOM customization
  • ptOptions: PassThrough configuration options
  • unstyled: Removes built-in component styles

StepperCommandDialog supports the following result callbacks that are invoked based on the command execution outcome:

  • onSuccess(response: TResponse): Invoked when the command executes successfully. Receives the typed response.
  • onFailed(commandResult: CommandResult<TResponse>): Invoked when command execution fails for any reason.
  • onException(messages: string[], stackTrace: string): Invoked when the command throws an exception.
  • onUnauthorized(): Invoked when authorization fails.
  • onValidationFailure(validationResults: ValidationResult[]): Invoked on validation errors.

Multiple callbacks may fire for the same execution. For example, both onFailed and onValidationFailure will be invoked for validation errors.

  • onConfirm is executed only after command execution succeeds.
  • If onConfirm returns true, the dialog closes; otherwise it stays open.
  • If onConfirm is not provided, onClose(DialogResult.Ok) is used.
  • onCancel follows the same behavior as Dialog (true closes).
  • onClose closes unless it returns false.

The step number circles in the wizard navigation bar reflect the validation state of each step:

Circle colorMeaning
RedThe step contains at least one field with a validation error
GreenThe step has been visited (navigated through) and all its fields are valid
Default (theme primary)The step has not been visited yet

Steps that are not currently active are dimmed to keep visual focus on the current step.

To show validation indicators immediately on open — before the user has touched any fields — pass the validateOnInit prop:

<StepperCommandDialog
command={CreateProject}
validateOnInit
...
>

This is useful when the dialog opens with pre-populated values that may already be partially invalid.

Step positionFooter content
First stepNext
Middle stepPrevious, Next
Last step (invalid)Previous
Last step (valid)Previous, Submit

Cancel is always available via the X button in the dialog header. The Submit button is hidden until the user reaches the last step and all command form fields across every step pass validation.

StepperCommandDialog automatically manages a busy state during command execution:

  • When Submit is clicked, the Submit button shows a loading spinner and all navigation buttons are disabled.
  • Once execution completes (success or failure), the buttons return to their normal state.

Each step is defined by a StepperPanel from primereact/stepperpanel. The header prop sets the step title shown in the stepper navigation:

<StepperPanel header="Contact Details">
<InputTextField<MyCommand> value={c => c.email} title="Email" />
</StepperPanel>

CommandForm fields placed inside a StepperPanel are automatically bound to the same command instance, regardless of which step they are on.

StepperCommandDialog integrates with:

  • @cratis/arc/commands for command execution
  • @cratis/arc.react/commands for form handling
  • PrimeReact Stepper and StepperPanel components for the wizard UI
  • PrimeReact Dialog component for the modal wrapper