Skip to content

Components

Multi-Step Dialogs — Two Hard Patterns in One Box, Done Carefully

Three Steps Max, Height That Doesn't Jump, and the Dirty-State Guard on Escape
Written by Aiden Wood Founder and Lead Design Engineer
🪟 🪜 🛡️

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.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.