Dialog
Modal dialog on Radix Dialog: a titled panel with body and footer slots, focus trapping, Escape and backdrop dismiss, and entry/exit animation.
// Radix — @radix-ui/react-dialog
import { CloseButton, Dialog, DialogClose } from "@shavin/ui";Opened from a trigger
The simplest form: Dialog keeps its own open state. DialogClose closes it from a footer button.
The simplest form: Dialog keeps its own open state. DialogClose closes it from a footer button.
import { Dialog, DialogClose, Button } from "@shavin/ui";
<Dialog
trigger={<Button>Export data</Button>}
title="Export data"
description="Download every project as a CSV file."
footer={
<DialogClose asChild>
<Button>Export</Button>
</DialogClose>
}
/>Controlled
Hold the open state yourself when something else opens or closes the dialog. Compose any content in the body: forms, Tabs, Grid.
Hold the open state yourself when something else opens or closes the dialog. Compose any content in the body: forms, Tabs, Grid.
const [open, setOpen] = useState(false);
<Button variant="soft" onClick={() => setOpen(true)}>Rename project</Button>
<Dialog
open={open}
onOpenChange={setOpen}
size="md"
title="Rename project"
footer={
<>
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<Button onClick={() => setOpen(false)}>Save</Button>
</>
}
>
<TextField label="Project name" defaultValue="Website redesign" />
</Dialog>Sizes
Component Source
<Dialog open={open} onOpenChange={setOpen} size="sm" title="Small dialog">…</Dialog>
<Dialog open={open} onOpenChange={setOpen} size="md" title="Medium dialog">…</Dialog>
<Dialog open={open} onOpenChange={setOpen} size="lg" title="Large dialog">…</Dialog>Non-dismissible
Component Source
<Dialog
open={open}
onOpenChange={setOpen}
dismissible={false}
title="Try clicking outside"
footer={<Button onClick={() => setOpen(false)}>Close</Button>}
>
Clicking the backdrop won't close this one. Escape and the close button still work.
</Dialog>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title* | ReactNode | — | Heading shown at the top of the dialog (also its accessible name). |
| description | ReactNode | — | Supporting line under the title (also its accessible description). |
| subtitle | ReactNode | — | @deprecated Use `description`. |
| open | boolean | — | Controlled open state. Pair with `onOpenChange`. |
| defaultOpen | boolean | — | Initial open state when uncontrolled. Default: closed when `trigger` is set, otherwise open. |
| onOpenChange | (open: boolean) => void | — | Called whenever the dialog asks to open or close (trigger, Escape, backdrop, close button). |
| trigger | ReactNode | — | Element that opens the dialog, e.g. `<Button>Edit profile</Button>`. |
| onClose | () => void | — | Called after the close animation finishes. Use it to unmount a dialog you render conditionally. |
| children | ReactNode | — | Dialog body. |
| footer | ReactNode | — | Footer actions, right-aligned. Wrap a button in `<DialogClose asChild>` to close from it. |
| dismissible | boolean | true | Whether clicking the backdrop closes the dialog. Default true. |
| layout | "default" | "centered" | "bare" | — | Header treatment. `default`: left-aligned title row with a close button. `centered`: centred title and description, no header row (for confirmations, success and invite moments). `bare`: no header row; the title and description sit above the content with no chrome (for forms and pickers that lead with their content). |
| divided | boolean | — | Hairlines between header, body and footer. Default: on for `default`, off for `centered` and `bare`. |
| footerAlign | "start" | "center" | "end" | "between" | "stretch" | `end` | Footer button alignment. `stretch` makes buttons share the row (good on mobile). Default `end`. |
| size | "sm" | "md" | "lg" | "sm" | — |
* required
Keyboard
| Key | Action |
|---|---|
| Tab | Moves focus to the next focusable element (trapped within the dialog). |
| Shift + Tab | Moves focus to the previous focusable element. |
| Escape | Closes the dialog and returns focus to the trigger. |
Data attributes
| Attribute | Values |
|---|---|
| [data-state] | "open" | "closed" — on the overlay and content while mounted. |