Onboarding, "create project", invite-your-team — short flows that want focus but don't deserve a page. So they land in a multi-step dialog, which quietly combines the two most bug-prone patterns in UI: wizard state (covered in the multi-step form post) and modal behaviour. Each is fine alone; the collisions are where it breaks.
Velocity X's standard-multi-step-dialog resolves the collisions with three rules.
The Money Pattern
Rule one: Escape checks for dirt. A modal convention says Escape closes; a wizard holding four fields of typed data says that's destructive. The resolution is a dirty-state guard:
const onEscape = () => {
if (!isDirty) return close(); // pristine → close freely
setConfirming(true); // dirty → "Discard setup?" inline
};
// The confirm is INSIDE the dialog — never a second stacked modal:
{confirming && (
<div role="alertdialog" aria-label="Discard changes?" class="border-t p-4">
<p>Discard this setup? Your answers will be lost.</p>
<button onClick={close}>Discard</button>
<button autofocus onClick={() => setConfirming(false)}>Keep editing</button>
</div>
)}
Rule two: the dialog's height doesn't jump between steps. Measure the tallest step (or set a min-height) so advancing doesn't make the whole box lurch and the buttons chase the cursor. Rule three: on step change, focus moves to the new step's heading — not the first input (presumptuous) and not nowhere (screen-reader limbo).
The Catch
The honest question before any of this: should the flow be in a dialog at all? Three steps of short fields, yes. Five steps, file uploads, or anything someone might half-finish and return to — that's a page with a URL, because dialogs die with the tab and can't be bookmarked, shared or resumed. The dialog version of a long flow is a data-loss machine with nice padding.
And the progress indicator inside a dialog is dots or "Step 2 of 3" text — a full breadcrumb stepper inside a 480px box crowds the content it's describing.
The Verdict
Dirty-guarded Escape, stable height, focus-to-heading, three steps max — and the self-awareness to use a page when the flow outgrows the box. The assembled dialog is in Velocity X's Standard Overlays & Menus, sharing its wizard state with the full-page variant so outgrowing the dialog is a refactor, not a rewrite.









