Dialog
v1.0.18Updated 20 Oct 2026Modal dialog (Radix). Blocking overlay for confirmations, forms, or focused tasks. Ships with tonal headers, a confirm pattern, multi-step stepper, and form-dialog layout for richer flows.
Preview
Live · 14 stories▸Why this is recommendedmodaloverlaypopupradix+4
The default, out-of-the-box Dialog.
- ✓Confirmation prompts
- ✓Short forms
- ✓Important alerts
- ✓Destructive confirms
- ✓Multi-step wizards
- ✓Form dialogs
- Focus trap
- Escape to close
- Composable header / footer
- Tonal header on the shared Tone vocabulary (neutral / primary / success / warning / danger / info) — the same words Button, Badge and Alert take
- Deprecated tone spellings still render: destructive is danger, default is neutral
- Tolerates a bad tone or size: an unrecognised value falls back to the neutral tone / md size instead of throwing and blanking the page
- Confirm pattern with primary danger action
- Stepper wizard variant
- Form dialog variant
- Loading state on primary button
- Composition safety: dialog parts (DialogHeader / DialogBody / DialogFooter) passed to the root without a DialogContent are wrapped in one, so a controlled-only dialog is a real modal instead of inline page content; a development warning names the repair
- i18n: labels prop on the Dialog root overrides the built-in Close/Cancel strings (close aria-label, sr-only close text, footer Close button, confirm-footer Cancel fallback); merged over DEFAULT_DIALOG_LABELS
- closeOnOutsideClick={false} keeps a form-holding dialog open when the overlay is clicked, while the ✕, the footer buttons and Escape all still close it — unlike closable={false}, which removes those too. Works in compositional mode as well and does not trigger Pro mode (fb_8e8e3cf7)
- ✕Slide-in panels (use Sheet)
- ✕Tooltips (use Tooltip)
- ✕Toasts (use Sonner)
Install
Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.
Usage
Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.
Props
openControlled open state
—defaultOpenInitial open state for uncontrolled usage (forwarded to the Radix root; ignored when `open` is provided)
—onOpenChangeOpen state callback
—triggerThe element that opens the dialog, rendered inside a Radix Trigger with asChild — so pass one element that accepts a ref, e.g. a Button. Supplying it switches the dialog into Pro mode; a compositional dialog uses <DialogTrigger> instead
—closableWhether the dialog offers the usual ways out (default true). `false` removes the ✕ button entirely AND blocks Escape, for a dialog the user must answer — and it switches the dialog into Pro mode, so a compositional <DialogContent> cannot reach it. That is the difference from `closeOnOutsideClick`, which only governs the overlay click; when both are set, `closable={false}` wins and nothing but your own buttons closes the dialog
—confirmDeclarative confirm footer: { confirmLabel, onConfirm, cancelLabel?, onCancel?, destructive? }. Renders Cancel + a primary action, gives the content role="alertdialog" instead of "dialog", and moves opening focus to Cancel — the least destructive choice. `destructive` defaults to the dialog tone being danger. `onConfirm` may return a Promise but the dialog does not await it — drive the spinner yourself with `loading`, which disables the confirm button and puts a spinner in it
—stepsWizard stepper rendered above the content, one entry per step: { id, label }. An empty array renders nothing
—activeStepIdWhich `steps` entry is current, matched by id. Left out, the FIRST step is shown as active — an unknown id marks none of them, so keep it in step with the ids you passed
—toneHeader tone, on the catalog-wide Tone vocabulary. The old spellings still work and render identically: destructive is a deprecated alias of danger, default a deprecated alias of neutral. An unrecognised value falls back to neutral rather than throwing
—sizePanel width. An unrecognised value falls back to md
—loadingPrimary action loading state
—labelsOverride the built-in Close/Cancel strings (i18n). Merged over DEFAULT_DIALOG_LABELS; works in compositional and Pro modes and does not trigger Pro mode
—closeOnOutsideClickWhether a click on the dimmed overlay closes the dialog (default true — the behaviour every dialog has always had). Set false for a dialog holding a form: a stray overlay click loses a half-filled invoice and nothing about the gesture says "discard my work". The ✕, the footer buttons and Escape all still close it, which is the difference from closable={false} — that one hides the ✕, blocks Escape and switches the dialog into Pro mode. This prop does neither and reaches a compositional DialogContent too (fb_8e8e3cf7)
—Every tonal component shares the same tone × emphasis API, so the pair looks identical across Button, Badge, Alert and more.