--- title: Dialog description: Dialogs interrupt the page to capture a decision or short form. They trap focus and return it when dismissed. category: Overlays --- import { meta as DialogMeta, Alert, Default } from '@/content/stories/dialog'; import Canvas from '@/components/component-docs/canvas'; import Demo from '@/components/component-docs/demo'; export const config = { dependencies: { components: [Canvas, Demo], scripts: [ '../../components/component-docs/demo.script.tsx', '../../components/component-docs/canvas.script.tsx', '../../components/component-docs/controls.script.tsx', ], }, }; # Dialog

Dialogs interrupt the page to capture a decision or short form. They trap focus and return it when dismissed.

## Try it ## Usage Register dialogs with `installDialogs`, then open them imperatively via `openDialog` or a trigger with `data-dialog-open`. Compose title, body, and actions with the sub-components. ```tsx import { RuiDialog, RuiDialogTitle, RuiDialogBody, RuiDialogActions, RuiDialogClose, installDialogs, openDialog, } from '@ecopages/radiant-ui/dialog'; installDialogs(); Edit profile Update your display name and email. Cancel ``` ## Custom markup `` coordinates any light-DOM tree that matches its query contract. The `Rui*` helpers stamp these targets; they are not required. ```tsx import '@ecopages/radiant-ui/dialog';
; ``` BEM classes are presentation-only. Set `alert` on the host for `role="alertdialog"` on `[data-ref="dialog"]`. ## Alert dialogs

Set `alert` to `true` for destructive confirmations. Alert dialogs limit tab order to the dialog actions.

## Return focus on close

Focus returns to the element that opened the dialog. Avoid stacking multiple modal layers.

## Theming Dialog surfaces map to **semantic surface roles**, never Tailwind palette steps. Override `--rui-dialog-*` on `rui-dialog`. | Part | Default | Override | | --- | --- | --- | | Backdrop | `overlay` scrim | theme `--color-overlay` | | Surface fill / radius / shadow | `--background`, `--radius-container`, `--shadow-modal` | `--rui-dialog-surface`, `--rui-dialog-radius`, `--rui-dialog-shadow` | | Surface padding / max width | `--space-inset`, `28rem` | `--rui-dialog-padding`, `--rui-dialog-max-width` | | Narrow viewport inset | `1rem` | `--rui-dialog-inset-x` | | Title | `on-background` | theme | | Close button | `on-surface` | theme | ```css rui-dialog { --rui-dialog-max-width: 40rem; --rui-dialog-padding: var(--space-6); } ``` ## Accessibility - Every dialog needs an accessible name via `label` or `RuiDialogTitle`. - Use `alert` for confirmations that require an explicit decision before continuing. - Do not open a dialog without a clear way to dismiss it; provide a close action. ## API `RuiDialog` is a custom element (``) with a composition-first surface. Pass `title` / `actions` for the composite API, or compose the view helpers as children. ### Attributes (``) | Attribute | Type | Default | Description | | --- | --- | --- | --- | | `open` | `boolean` | `false` | Whether the dialog is open. | | `alert` | `boolean` | `false` | Uses `role="alertdialog"` for workflow-interrupting confirmations. | | `label` | `string` | `''` | Accessible name when there is no visible title. | ### Light-DOM contract | Target | Required | Host writes | Author owns | | --- | --- | --- | --- | | `[data-ref="root"]` | yes | `hidden` when closed | the wrapper node | | `[data-ref="backdrop"]` | yes | — | the scrim node; click dismisses | | `[data-ref="dialog"]` | yes | `aria-labelledby`, `aria-label`, `aria-describedby` | `role`, `aria-modal`, `tabIndex` (view seeds these) | | `[data-dialog-title]` | no | `id`, `aria-labelledby` wiring | visible title text | | `[data-dialog-body]` | no | `id`, `aria-describedby` wiring | body content | | `[data-dialog-close]` | no | — | dismiss control; click emits `rui-close` | Do not set `hidden` on `[data-ref="root"]` or `aria-*` on `[data-ref="dialog"]`. Nested hosts: none. ### Events | Event | Detail | Description | | --- | --- | --- | | `rui-close` | `{ reason: 'escape' \| 'backdrop' \| 'dismiss' }` | Emitted when the dialog is dismissed. | ### View helpers | Component | Target stamped | Notes | | --- | --- | --- | | `RuiDialog` | `DialogShell` targets | Pass `title` / `actions` for composite API, or compose helpers as children. | | `RuiDialogTitle` | `[data-dialog-title]`, `data-ref="title"` | Visible accessible name. | | `RuiDialogBody` | `[data-dialog-body]`, `data-ref="description"` | `aria-describedby` target. | | `RuiDialogActions` | — | Action row; not queried by the host. | | `RuiDialogClose` | `[data-dialog-close]`, `data-ref="close"` | Emits `rui-close` with reason `dismiss`. | ### CSS classes Public BEM classes (documented via `@cssclass`): | Class | Description | | --- | --- | | `.rui-dialog` | Root; hidden until `open`. | | `.rui-dialog__backdrop` | Scrim using the `overlay` role. | | `.rui-dialog__surface` | Modal panel: `background` + `rounded-container` + `shadow-modal`. | | `.rui-dialog__title` | Dialog title; `aria-labelledby` target. | | `.rui-dialog__body` | Dialog body; `aria-describedby` target. | | `.rui-dialog__actions` | Right-aligned action row. | | `.rui-dialog__close` | Dismiss button. | ### Theme roles | Part | CSS variables consumed | | --- | --- | | Backdrop | `--overlay` | | Surface | `--background`, `--on-background`, `--shadow-modal`, `--radius-container`, `--p-inset` | | Close button | `--on-surface` |