Dialog
A headless, accessible modal dialog with focus trapping, keyboard dismissal, and composable parts.
Features
- Focus trapping
- Focus restoration
- Escape key dismissal
- Controlled or uncontrolled open state
- Accessible title and description wiring
- Headless styling
Installation
npm install @ariaui/dialog
Examples
Modal dialog with focus trapping and Escape to dismiss. Compose Root, Trigger, Overlay, Content, and related parts. The sample wraps Overlay and Content in Portal.Root so the layer stacks above the page—style with className using your design tokens.
Edit profile dialog
Portal-backed modal dialog with title, description, form fields, and action buttons.
No preview output yet.
Framer Motion dialog
Dialog overlay and content animated with Framer Motion through asChild composition.
No preview output yet.
Anatomy
import * as Dialog from "@ariaui/dialog";
export default function Example() {
return (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.Cancel />
<Dialog.Action />
<Dialog.Close />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}
API Reference
Root
State container. Owns the open/closed state and provides context to all child components.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
onClose | () => void | — |
Trigger
Button that toggles the dialog open state.
| Attribute | Values |
|---|---|
| aria-haspopup | dialog |
| aria-expanded | "true" when open, "false" when closed |
| aria-controls | ID of the Content element |
| [data-state] | "open" | "closed" |
Portal
Portal container for dialog layers. Renders children into document.body in the browser and inline during SSR.
Overlay
Background overlay rendered behind the dialog content. Typically styled with a semi-transparent background.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| [data-state] | "open" | "closed" |
Content
Dialog content container. Traps focus within the dialog, handles Escape dismissal, and restores focus on close.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| role | dialog |
| aria-modal | true |
| aria-labelledby | ID of the Title element |
| aria-describedby | ID of the Description element |
| [data-state] | "open" | "closed" |
Title
Accessible title for the dialog. Referenced by Content via aria-labelledby.
Description
Accessible description for the dialog. Referenced by Content via aria-describedby.
Close
Button that closes the dialog when clicked. Use for auxiliary close actions (e.g., X icon).
Cancel
Cancel button that closes the dialog when clicked. Use for secondary/destructive cancel actions.
| Attribute | Values |
|---|---|
| data-dialog-cancel | Present when rendered |
Action
Action button that calls the onClick handler, then closes the dialog (unless preventDefault is called). Use for primary confirmation actions.
| Attribute | Values |
|---|---|
| data-dialog-action | Present when rendered |
Keyboard
| Shortcut | Action |
|---|---|
| Esc | Close the dialog and return focus to the trigger. |
| Tab | Move focus to the next focusable element within the dialog (loops to first). |
| Shift+Tab | Move focus to the previous focusable element within the dialog (loops to last). |
| Enter/Space | Activate the focused button (trigger, close, or any action button). |
Accessibility
The Dialog component implements the WAI-ARIA Dialog (Modal) pattern:
Contentrenders withrole="dialog"andaria-modal="true"to mark the surface as modal.Contentis labelled viaaria-labelledbypointing to theTitleandaria-describedbypointing to theDescription.Triggerexposesaria-haspopup="dialog",aria-expanded, andaria-controlsfor assistive technology.- Focus is trapped within the dialog using FocusScope — Tab loops through focusable elements.
Escapecloses the dialog from any focusable element inside it.- Focus is restored to the trigger element when the dialog closes.