Dialog
A modal dialog compound that wraps Radix Dialog with the full anatomy — Trigger, Content, Header, Body, Footer, Title, Description and Close. Use it when an action must block the flow and demand a decision. It traps focus, restores focus to the trigger on close, and is dismissible via the close button, backdrop, or Escape — each opt-outable.
import { Dialog } from "@idinstudio/ui";Preview
Real, interactive examples rendered from the live component.
Props
Every styling and behavioural attribute is a typed prop — no className at the usage site.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. Pair with onOpenChange. |
defaultOpen | boolean | — | Uncontrolled initial open state. |
onOpenChange | (open: boolean) => void | — | Fires whenever the open state changes. |
modal | boolean | true | When false the underlying page stays interactive (non-modal). |
Content.size | "sm" | "md" | "lg" | "full" | "md" | Panel width preset. full renders an edge-to-edge sheet with inset. |
Content.closeOnOutsideClick | boolean | true | When false, clicking the backdrop does not close the dialog. |
Content.closeOnEscape | boolean | true | When false, Escape does not close the dialog. |
Content.showCloseButton | boolean | true | When false, hides the top-right X close affordance. |
Guidelines
When to reach for this component, and when not to.
Do
Use Dialog when a decision must block the flow — destructive confirms, required input.
Write the title as a question with a specific noun — "Delete workspace?".
State the consequence and permanence in the description before a destructive action.
Keep the primary action in the Footer and label it with the exact verb-object.
Don't
Don't use a Dialog for transient acknowledgements — use a Toast.
Don't write vague titles like "Are you sure?" or "Confirm action".
Don't disable every dismissal (Escape, backdrop, X) without an explicit Footer choice.
Don't nest dialogs or trigger one from inside another.
Accessibility
The component's a11y contract. WCAG 2.1 AA is the non-negotiable baseline.
Keyboard
| Key | Action |
|---|---|
| Tab | Move focus forward within the dialog (trapped). |
| Shift + Tab | Move focus backward within the dialog. |
| Esc | Close the dialog (unless closeOnEscape={false}). |
| Enter / Space | Activate the focused button. |
ARIA & screen reader
- Content has role="dialog" and aria-modal="true" when modal (the default).
- Dialog.Title and Dialog.Description wire to the content via aria-labelledby / aria-describedby.
- On open, focus moves to the first focusable element inside the content and is trapped.
- On close, focus returns to the trigger element.
- The title renders inside an <h2> (Radix); the close button is labelled aria-label="Close".
- Announces "<Title>, dialog" on open.