Dialog
A dialog asks for a decision or reports a result on top of the page. It’s called Modal in Figma.
<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>When to use
Section titled “When to use”- 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.
When not to use
Section titled “When not to use”- 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
sizefirst, then a page. - Never open a dialog from another dialog. Use steps with a back button instead.
Anatomy
Section titled “Anatomy”- 1TrayThe sheet. Grey with the sidebar's grain in a decision dialog, it holds the actions.
- 2BackOptionalGoes to the previous step of a flow.
- 3Title and descriptionSays what the dialog is for. Title in heading/sm, description in body/sm.
- 4CloseOptionalOnly when no footer button closes the dialog.
- 5BodyThe white panel's content. Items sit 24px apart.
- 6FooterOptionalThe actions, right-aligned on the tray.
Decision
Section titled “Decision”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).
Standalone
Section titled “Standalone”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.
Without a footer
Section titled “Without a footer”A picker, where choosing an option is the action, has no footer. Keep the close button so there is a way out.
Actions
Section titled “Actions”- 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.
Content
Section titled “Content”- 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.
Behaviour
Section titled “Behaviour”| 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: callpreventDefault()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.
Accessibility
Section titled “Accessibility”- Every dialog needs a title, which names it for screen readers. If the design hides it, keep it with
srOnlyTitle. - Use
alertfor 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.
DialogContent
Section titled “DialogContent”| 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. |
DialogHeader
Section titled “DialogHeader”| 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.
Related
Section titled “Related”- A Button runs the dialog’s actions.