RoadieRoadie
  • Home
  • Brand
  • Foundations
  • Content
  • Tokens
  • Components
  • Charts
  • Widgets
  • Appearance
HomeBrandFoundations
Appearance

Components

  • Navigation

    • Breadcrumb
    • LinkBeta
    • NavigatorAlpha
    • Steps
    • Tabs
  • Layout

    • Accordion
    • CollapsibleBeta
    • PaneAlpha
    • ScrollArea
    • Separator
  • Actions

    • Button
    • IconButton
    • ToggleBeta
    • Toggle groupBeta
    • ToolbarBeta
  • Fields

    • EditorAlpha
    • Field
    • Fieldset
    • Input
    • Label
    • Number fieldBeta
    • OTP fieldBeta
    • Query fieldAlpha
    • Textarea
  • Choices

    • Autocomplete
    • CheckboxBeta
    • Combobox
    • Radio group
    • Select
    • SliderBeta
    • SwitchBeta
  • Date and time

    • CalendarBeta
    • CalendarTile
    • Countdown
    • Dashboard periodBeta
    • Date fieldBeta
    • Date pickerBeta
    • Date range pickerBeta
    • DateTime
    • Duration
    • Time fieldBeta
  • Collections

    • Card
    • Carousel
    • DataTableBeta
    • ListAlpha
    • Marquee
    • RecordGridAlpha
    • RecordTableAlpha
    • SortableAlpha
    • TableBeta
  • Overlays

    • Dialog
    • Drawer
    • MenuBeta
    • Popover
    • ToastBeta
    • Tooltip
  • Status

    • Badge
    • CalloutBeta
    • DeltaBeta
    • Empty state
    • MeterBeta
    • ProgressBeta
    • SkeletonBeta
    • SparklineBeta
    • StatTileBeta
  • Media & brand

    • AvatarBeta
    • Icon Tile
    • Image
    • Logo
    • PatternBeta
    • QR codeBeta
    • SpotIllustration
  • Text

    • Code
    • Highlight
    • KbdBeta
    • Mark
    • Prose

Dialog

Status
Stable
Added
Components 2.7.016 Jun 2026
Updated
Components 2.14.023 Sept 2026
Docs updated
19 Oct 2026

A modal overlay that interrupts the page for a focused task, built on Base UI's dialog primitive.

Import

import { Dialog } from '@oztix/roadie-components/dialog'

Examples

Each example leads with an IconTile (size='2xl' shape='circle', its intent inherited from the dialog) centred above the title. Dialog.Header handles the centring.

Default

A trigger opens a centred modal over a dimmed backdrop. Dialog.Content collapses the underlying Portal, Backdrop, Viewport, and Popup into a single element.

<Dialog>
<Dialog.Trigger render={<Button>Open dialog</Button>} />
<Dialog.Content>
<Dialog.Header>
<IconTile size='2xl' shape='circle'>
<Envelope weight='duotone' />

Emphasis

emphasis on the root sets how much the dialog takes over the page behind it. It defaults to normal, which dims and blurs the page, because a dialog asks for the user's full attention. subtle tints the page and leaves it readable, and subtler leaves it clear.

{['normal', 'subtle', 'subtler'].map((emphasis) => (
<Dialog key={emphasis} emphasis={emphasis}>
<Dialog.Trigger render={<Button>{emphasis}</Button>} />
<Dialog.Content size='sm'>
<Dialog.Header>
<Dialog.Close render={<IconButton aria-label='Close' emphasis='normal' size='sm' className='absolute left-0 top-0'><X weight='bold' /></IconButton>} />

Sizes

Use the size prop on Dialog.Content to set the maximum width. Defaults to md.

<Dialog>
<Dialog.Trigger render={<Button>Small</Button>} />
<Dialog.Content size='sm'>
<Dialog.Header>
<Dialog.Close render={<IconButton aria-label='Close' emphasis='normal' size='sm' className='absolute left-0 top-0'><X weight='bold' /></IconButton>} />
<IconTile size='2xl' shape='circle'>

Intents

Portaled popups sit outside the trigger's CSS cascade, so set the colour context directly on Dialog.Content with the intent prop. Each intent fits a different moment:

  • info and success for informational modals (dismiss-only, with a header close)
  • warning and danger for caution and destructive confirmations
  • accent to promote an action
<Dialog>
{/* Info for an informational, dismiss-only modal */}
<Dialog.Trigger render={<IconButton aria-label='Release notes' emphasis='subtle'><Info weight='bold' /></IconButton>} />
<Dialog.Content intent='info' size='sm'>
<Dialog.Header>
<Dialog.Close render={<IconButton aria-label='Close' emphasis='normal' size='sm' className='absolute left-0 top-0'><X weight='bold' /></IconButton>} />

Alert dialog

Set role='alertdialog' on the root for a blocking message that demands a response. Examples are a session timeout, a cart-expiry warning or an irreversible confirmation. This exposes the surface as role="alertdialog" and raises the backdrop and surface to the z-alert tier so the dialog stacks above an already-open dialog or drawer. The default role='dialog' stays on the z-overlay / z-modal tiers.

<Dialog role='alertdialog' open={expired} onOpenChange={onClose}>
<Dialog.Content size='sm'>
<Dialog.Header>
<Dialog.Title>Your cart has expired</Dialog.Title>
</Dialog.Header>
<Dialog.Footer>

Composition

Dialog is a compound component. Use Dialog.Header, Dialog.Body, and Dialog.Footer to structure the modal, and Dialog.Close to dismiss it.

<Dialog>
<Dialog.Trigger render={<Button>View details</Button>} />
<Dialog.Content>
<Dialog.Header>
<Dialog.Close render={<IconButton aria-label='Close' emphasis='normal' size='sm' className='absolute left-0 top-0'><X weight='bold' /></IconButton>} />
<IconTile size='2xl' shape='circle'>

With footer actions

A Dialog.Footer holds a centered actions row. Combine it with intent='danger' for a confirm-deletion flow.

<Dialog role='alertdialog'>
<Dialog.Trigger render={<Button intent='danger' emphasis='strong'>Delete account</Button>} />
<Dialog.Content intent='danger' size='sm'>
<Dialog.Header>
<IconTile size='2xl' shape='circle'>
<Warning weight='duotone' />

Guidelines

Use a dialog for tasks that need the user's full attention, such as confirmations, short forms, and destructive actions. Keep content concise, and set intent on Dialog.Content, not the trigger, since portaled popups do not inherit the trigger's CSS cascade. Write the title, description, and buttons with Interface copy.

Use alertdialog for blocking or destructive confirmations

<Dialog role='alertdialog'>
<Dialog.Content intent='danger' size='sm'>
<Dialog.Title>Delete event?</Dialog.Title>
…
</Dialog.Content>
</Dialog>

Do

Set role='alertdialog' when the user must resolve the dialog before moving on. Examples are deleting data, discarding edits, or a session or cart expiry. Screen readers announce it assertively, and it stacks above an already-open dialog or drawer on the z-alert tier.

<Dialog>
<Dialog.Content intent='danger' size='sm'>
<Dialog.Title>Delete event?</Dialog.Title>
…
</Dialog.Content>
</Dialog>

Don’t

Don't leave a destructive or blocking confirmation as the default role='dialog'. It is announced as a plain dialog and can be obscured by an open drawer. Keep role='dialog' for informational or optional content.

Use one prominent action, the rest normal

Do

Give the dialog one prominent button. Use emphasis='strong' with an accent intent, or danger for a destructive task. Leave the rest as default buttons. The primary path stays obvious at a glance.

Don’t

Never use emphasis='subtle' for footer actions, and never give a dialog more than one accent or strong button. Competing prominent buttons make the user stop and weigh every option instead of following the intended path.

Dismiss with a header close, not a lone Cancel

Do

When the only action is to close, put a Close icon button in the top-left of the header and skip the footer entirely. The dialog reads as informational, not a decision awaiting a choice.

Don’t

A lone Cancel in the footer wastes the prominent action slot and adds a step. There is nothing to cancel. The user only wants to close.

Lead notable dialogs with a matching icon

Do

For confirmations and notable moments, centre a size='2xl' shape='circle' IconTile above the title and leave its intent unset so it inherits the dialog's. That gives a danger or warning tile for caution, and success for completion. It signals the nature of the action before the title is read.

Don’t

Don't give the tile an intent that clashes with the dialog, shrink it until it reads as decoration, or add one to routine dialogs where it is just noise.

Accessibility

  • Keyboard: Escape closes the dialog and returns focus to the trigger. Focus is trapped within the dialog while it is open.
  • Default action: Enter activates the strong primary action (the emphasis='strong' button), like a form's default submit. It is ignored while focus is on another button, a multi-line textarea, or editable content so those keep their own Enter behaviour.
  • Focus: Focus moves into the dialog on open and is restored to the trigger on close.
  • ARIA: The popup is exposed with role="dialog" and aria-modal, with Dialog.Title/Dialog.Description providing the accessible name and description. Set role='alertdialog' for a blocking message that needs a response. This also raises the dialog to the z-alert tier so it stacks above an open dialog or drawer.
  • Icon-only close: When the dismiss control shows only an icon, give it an explicit label so screen readers announce its purpose. For example, <Dialog.Close render={<IconButton aria-label='Close'><XIcon weight='bold' /></IconButton>} />.

API reference

Dialog

openboolean

Whether the dialog is currently open.

defaultOpenboolean

Whether the dialog is initially open. To render a controlled dialog, use the `open` prop instead.

Defaults to false.

modalboolean | "trap-focus"

Determines if the dialog enters a modal state when open. - `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled. When `modal` is `true` or `'trap-focus'`, render `<Dialog.Close>` inside `<Dialog.Popup>` so touch screen readers can escape the popup.

Defaults to true.

onOpenChange((open: boolean, eventDetails: DialogRootChangeEventDetails) => void)

Event handler called when the dialog is opened or closed.

onOpenChangeComplete((open: boolean) => void)

Event handler called after any animations complete when the dialog is opened or closed.

disablePointerDismissalboolean

Whether to prevent the dialog from closing on outside presses. For non-modal dialogs, this also prevents the dialog from closing when focus moves outside of it.

Defaults to false.

actionsRefRefObject<DialogRootActions | null>

A ref to imperative actions. - `unmount`: Ends the closing phase of the dialog after an externally controlled closing animation finishes. Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the dialog completes closing on its own. Whether it leaves the DOM is decided by `keepMounted` on the portal. - `close`: Closes the dialog imperatively when called.

handleDialogHandle<unknown>

A handle to associate the dialog with a trigger. If specified, allows external triggers to control the dialog's open state. Can be created with the Dialog.createHandle() method.

childrenReactNode | PayloadChildRenderFunction<unknown>

The content of the dialog. This can be a regular React node or a render function that receives the `payload` of the active trigger.

triggerIdstring | null

ID of the trigger that the dialog is associated with. This is useful in conjunction with the `open` prop to create a controlled dialog. There's no need to specify this prop when the dialog is uncontrolled (that is, when the `open` prop is not set).

defaultTriggerIdstring | null

ID of the trigger that the dialog is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog.

role"dialog" | "alertdialog"

`'alertdialog'` raises the dialog to the `z-alert` tier so it stacks above an open modal or drawer.

Defaults to 'dialog'.

emphasis"normal" | "subtle" | "subtler"

How much the dialog takes over the page behind it.

Defaults to 'normal'.

Dialog.Backdrop

classNamestring | ((state: DialogBackdropState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

Inherited from DialogBackdropProps

forceRenderboolean

Whether the backdrop is forced to render even when nested.

Defaults to false.

Dialog.Body

No additional props. It forwards all standard HTML attributes to the underlying element.

Dialog.Close

classNamestring | ((state: DialogCloseState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

Inherited from NativeButtonProps

nativeButtonboolean

Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).

Defaults to true.

Dialog.Content

classNamestring | ((state: DialogPopupState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

intent"neutral" | "brand" | "brand-secondary" | "brand-blue" | "brand-orange" | "brand-purple" | "accent" | "danger" | "success" | "warning" | "info" | null
size"sm" | "md" | "lg" | null

Inherited from DialogPopupProps

initialFocusboolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | void | HTMLElement | null)

Determines the element to focus when the dialog is opened. By default, focus moves to the first tabbable element inside the popup, except when the dialog is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (first tabbable element or popup). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.

finalFocusboolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null)

Determines the element to focus when the dialog is closed. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (trigger or previously focused element). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.

Dialog.Description

No additional props. It forwards all standard HTML attributes to the underlying element.

Dialog.Footer

No additional props. It forwards all standard HTML attributes to the underlying element.

Dialog.Header

No additional props. It forwards all standard HTML attributes to the underlying element.

Dialog.Popup

classNamestring | ((state: DialogPopupState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

intent"neutral" | "brand" | "brand-secondary" | "brand-blue" | "brand-orange" | "brand-purple" | "accent" | "danger" | "success" | "warning" | "info" | null
size"sm" | "md" | "lg" | null

Inherited from DialogPopupProps

initialFocusboolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | void | HTMLElement | null)

Determines the element to focus when the dialog is opened. By default, focus moves to the first tabbable element inside the popup, except when the dialog is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (first tabbable element or popup). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.

finalFocusboolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null)

Determines the element to focus when the dialog is closed. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (trigger or previously focused element). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.

Dialog.Portal

classNamestring | ((state: DialogPortalState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

Inherited from DialogPortalProps

keepMountedboolean

Whether to keep the portal mounted in the DOM while the popup is hidden.

Defaults to false.

containerHTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null

A parent element to render the portal element into.

Dialog.Title

No additional props. It forwards all standard HTML attributes to the underlying element.

Dialog.Trigger

classNamestring | ((state: DialogTriggerState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

Inherited from DialogTriggerProps

handleDialogHandle<unknown>

A handle to associate the trigger with a dialog. Can be created with the Dialog.createHandle() method.

payloadunknown

A payload to pass to the dialog when it is opened.

idstring

ID of the trigger. In addition to being forwarded to the rendered element, it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop).

Inherited from NativeButtonProps

nativeButtonboolean

Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).

Defaults to true.

Dialog.Viewport

No additional props. It forwards all standard HTML attributes to the underlying element.

Previous page← TableNext pageDrawer →