Skip to content

Dialog

A dialog asks for a decision or reports a result on top of the page. It’s called Modal in Figma.

Type
Header
Footer
Title
JSX
<DialogContent>
  <DialogHeader title="Confirm withdrawal" description="Funds arrive in a few seconds." showClose={false} />
  <DialogBody>…</DialogBody>
  <DialogFooter>
    <Button variant="secondary">Cancel</Button>
    <Button>Confirm</Button>
  </DialogFooter>
</DialogContent>
  • To confirm an action before it runs, like a withdrawal, a bid or removing a team member.
  • To collect a few inputs without leaving the page, like editing a profile.
  • To report the result of something the person just did, like a completed swap.
  • For a note that needs no answer, use a toast.
  • For a warning that belongs to part of the page, use an alert there.
  • For something people do often, keep it on the page so it doesn’t interrupt them.
  • For long tasks, big tables or anything people should link to, use a page. If the content doesn’t fit, try a bigger size first, then a page.
  • Never open a dialog from another dialog. Use steps with a back button instead.
  1. 1TrayThe sheet. Grey with the sidebar's grain in a decision dialog, it holds the actions.
  2. 2BackOptionalGoes to the previous step of a flow.
  3. 3Title and descriptionSays what the dialog is for. Title in heading/sm, description in body/sm.
  4. 4CloseOptionalOnly when no footer button closes the dialog.
  5. 5BodyThe white panel's content. Items sit 24px apart.
  6. 6FooterOptionalThe actions, right-aligned on the tray.

Use decision, the default, when the dialog asks for a choice or some input: confirming, filling a form, picking an option. The header and body sit on a white panel, and the actions sit on the grey tray under it, right-aligned. The title is heading/sm and the description one line of body/sm. A confirm puts its explanation in the body as DialogDescription (body/md).

Use standalone to report a result: success, an error, a finished transaction or an announcement. It’s one white surface with a 96px illustration, a centred title (heading/md) and description (body/md), and buttons of equal width.

A flow that ends in a result can switch type on its last step.

Pass alert for a confirm that can’t be undone, like removing a team member. It’s a decision dialog with a Destructive main action and no close button. Screen readers announce it as an alert (role="alertdialog"), and a click outside doesn’t close it, so it can’t be dismissed by accident. Put Cancel first so it gets focus when the dialog opens.

A picker, where choosing an option is the action, has no footer. Keep the close button so there is a way out.

  • Put one main action on the right, as a Primary button. Use Destructive instead when it can’t be undone.
  • Put the dismiss action, like Cancel or Not now, to its left as a Secondary button.
  • Use two buttons at most. If you need a third, the dialog is probably doing too much.
  • On a phone the buttons stack at full width, with the main action on top.
  • Show the close button (X) only when no footer button closes the dialog. Turn it off with showClose={false}.
  • In a flow with steps, go back with the header’s back button (onBack), never with a Back button in the footer.
DoMake Cancel a secondary button, next to the main action.
Don'tDon't make it ghost. It reads as a link and gets missed.
  • Name the action or the result in the title as a verb and a noun, in sentence case, like Confirm withdrawal, Remove collaborator? or Swap complete.
  • Keep the header description to one line on what happens. It truncates past one line, so anything longer, like what can’t be undone, goes at the top of the body as DialogDescription.
  • Button labels repeat the title’s verb, like Withdraw for Confirm withdrawal. Avoid OK, Yes and Submit.
Confirm withdrawal
DoName the action or the result in a few words.
Are you sure?
Don'tDon't ask a vague question. The title should make sense on its own.
Key Action
Tab Moves focus through the dialog. Focus stays inside it.
Esc Closes the dialog.
  • It opens in 250ms, fading in and scaling up from 96%, and closes in 180ms on a gentler ease-out back to 96%, with the scrim moving in step. With reduced motion it only fades.
  • Keyboard focus shows a 2px ring with a 2px gap on every button. The header sits above the body, so the ring is never cut off.
  • Opening moves focus to the first thing you can use: the back or close button, the first field, or Cancel in an alert. Closing returns focus to the button that opened the dialog.
  • To start focus somewhere else, handle onOpenAutoFocus: call preventDefault() and focus a control inside the dialog yourself. Cancelling it alone leaves focus behind the scrim.
  • Clicking the scrim closes the dialog, except an alert.
  • When the content is taller than the screen, the body scrolls and the header and footer stay put.
  • While a transaction is running, pass dismissible={false}. It turns off Esc, the scrim click and the close button together.
  • Every dialog needs a title, which names it for screen readers. If the design hides it, keep it with srOnlyTitle.
  • Use alert for destructive confirms, so screen readers announce them as alerts.
  • The back and close buttons have the labels Back and Close.
  • The dialog traps focus and hides the page from assistive tech while it’s open.
Prop Type Default Notes
type "decision" | "standalone" "decision" Decision asks, standalone reports a result.
size "sm" | "md" | "lg" | "xl" | "2xl" "md" Max widths 400, 440, 540, 640 and 860px.
dismissible boolean true Off while a transaction runs.
alert boolean false A destructive confirm: role="alertdialog", no closing from outside.
Prop Type Default Notes
title ReactNode Required.
description ReactNode One or two lines under the title.
illustration ReactNode The 96px illustration in a standalone dialog.
onBack () => void Shows the back button.
showClose boolean true Turn off when a footer button closes the dialog.
srOnlyTitle boolean false Hides the header but keeps the title for screen readers.
media, badge ReactNode Code only: an avatar before the title, a badge before the close button.

DialogBody and DialogFooter take children and className. Dialog, DialogTrigger and DialogClose are Radix Dialog’s.

  • A Button runs the dialog’s actions.