Skip to content
ArcadiaDesign
Try it

TSX

Actions go right-aligned with the primary last and Cancel as a ghost button. A dialog sits on --bg-elevated with the float edge as its border, 16px continuous corners and the dialog shadow. It opens in 180ms: a fade while it rises 8px into place, both over --duration-dialog on --ease-in-out, with no zoom, and it leaves with a 140ms fade where it stands. The backdrop blurs the page by 8px under a light scrim, on the same times, so the dialog stands out by depth rather than by darkness.

Dialog, Confirm Dialog or Tray? A Dialog is for a task with its own controls, such as renaming or settings. A Confirm Dialog only stops something that can't be undone. A question the product asks during work belongs in a Tray docked to the composer, where it doesn't block the page.

DialogHeader, DialogTitle, DialogDescription and DialogBody have no props of their own: they take the props of the element they render (<div>, <h2>, <p> and <div>).

Examples

Controlled, with an async save

Hold open yourself to close on success: Save shows its loading state, the field and Cancel lock, and Esc or a click outside wait until the save settles.

Long body

The body scrolls; a divided footer keeps the actions anchored.

Sizes

Five widths, each capped by the viewport minus 32px. Rendered open in place.

320
400, the default
480
560
720

rootStyle on DialogContent takes where the dialog sits and its width, a token of its kind.

--dialog-w
TokenRef<Measure>Default 400px
Width (320 / 400 / 480 / 560 / 720 by size), capped by the viewport less a 16px gutter.

Modal by default: focus is trapped, the page is inert and scroll-locked, and focus returns to the trigger on close. The title names the dialog and the description describes it, so always render a DialogTitle. The close button in the corner is labelled "Close" (closeLabel changes it).

Esc
Closes the dialog
Tab
Cycles focus inside the dialog

Dialog

modal
boolean | "trap-focus"Default true
true: focus trapped, the page behind inert, its scroll locked. false: none of that. "trap-focus": focus trapped, the page left as it is.
disablePointerDismissal
booleanDefault false
A press outside (on the backdrop) doesn't close it.
open
boolean
Controlled open state.
defaultOpen
booleanDefault false
Initial open state when uncontrolled.
onOpenChange
(open: boolean, details: OpenChangeDetails) => void
Called when the popup opens or closes, with why (details.reason) and the event.
onOpenChangeComplete
(open: boolean) => void
Called once the open or close transition has finished.

render
RenderProp<{ disabled: boolean }>
Replace the rendered element, e.g. render={<a href="/settings" />}, or a function of props and state.
disabled
boolean
Native disabled: no pointer events, no tooltip, skipped by Tab.
focusableWhenDisabled
boolean
Keep a disabled control focusable and hoverable (aria-disabled), so a tooltip can say why.
nativeButton
boolean
Button semantics, inferred from what renders: a <button> is native, an <a> stays a link, anything else gets role="button" and key handling. false forces button semantics on whatever renders (a link acting as a button).

Rest props go to <button> props.

rootStyle
RootStyle<DialogKnobs>
Typed StyleX override for the dialog: layout and its --dialog-* knobs.
size
"sm" | "md" | "lg" | "xl" | "2xl"Default "md"
Width 320 / 400 / 480 / 560 / 720, capped by the viewport minus 32px.
placement
"center" | "top"Default "center"
top: a command palette, fixed in height so a query never moves it.
showClose
booleanDefault true
Top-right close button.
closeLabel
stringDefault "Close"
Accessible name of the close button.
container
PortalContainerDefault document.body
Portal container.
initialFocus
FocusTarget
Where focus goes on open: an element, false to stay, or a function of how it opened. Default: the first field or button inside.
finalFocus
FocusTarget
Where focus goes on close. Default: wherever it was before it opened.
className
string
A product's hook class for its own rules (being retired: new code sets rootStyle).

Rest props go to <div> props.

divided
boolean
Hairline above the actions (long bodies).

Rest props go to <div> props.

render
RenderProp<{ disabled: boolean }>
Replace the rendered element, e.g. render={<a href="/settings" />}, or a function of props and state.
disabled
boolean
Native disabled: no pointer events, no tooltip, skipped by Tab.
focusableWhenDisabled
boolean
Keep a disabled control focusable and hoverable (aria-disabled), so a tooltip can say why.
nativeButton
boolean
Button semantics, inferred from what renders: a <button> is native, an <a> stays a link, anything else gets role="button" and key handling. false forces button semantics on whatever renders (a link acting as a button).

Rest props go to <button> props.