---
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 profileUpdate 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';
Edit profile
Update your display name and email.
;
```
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` |