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";Real, interactive examples rendered from the live component.
<Dialog>
<Dialog.Trigger asChild><Button severity="danger">Delete</Button></Dialog.Trigger>
<Dialog.Content size="md">
<Dialog.Header>
<Dialog.Title>Delete workspace?</Dialog.Title>
<Dialog.Description>This cannot be undone.</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Close asChild><Button variant="ghost">Cancel</Button></Dialog.Close>
<Button severity="danger">Delete</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog>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. |
When to reach for this component, and when not to.
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 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.
The component's a11y contract. WCAG 2.1 AA is the non-negotiable baseline.
| 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. |