Dialog
A modal window, built on the native <dialog> element — so the focus trap, background inerting, Escape handling and top-layer stacking come from the platform rather than from JavaScript.
src/components/ui/dialog.tsxAbout
From the component's own source, where it was written.
A modal window, built on the native <dialog> element.
That gets the focus trap, background inerting, Escape handling and top-layer stacking from the platform rather than from JavaScript — the parts a hand-made modal usually gets subtly wrong.
Install
npx astralyx-ui add dialog
Usage
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogBody,
} from '@/components/ui/dialog'
<Dialog>
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
</DialogHeader>
<DialogBody>…</DialogBody>
</DialogContent>
</Dialog>Composer
Change the props and the source below follows.
<Dialog>
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>This is visible to everyone.</DialogDescription>
</DialogHeader>
<DialogBody>…</DialogBody>
<DialogFooter>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>Examples
Default
<Dialog>…</Dialog>
Not dismissable, no close button
<DialogContent showClose={false} dismissable={false}>…</DialogContent>API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
Dialog
A modal window, built on the native <dialog> element.
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | — | Controlled and uncontrolled open state, on Dialog. |
| defaultOpen | boolean | — | Controlled and uncontrolled open state, on Dialog. |
| onOpenChange | (open: boolean) => void | — | Fires on every change, including Escape and backdrop dismissal. |
| dismissable | boolean | true | On the root: false refuses Escape and backdrop presses together, for a dialog whose action is in flight. Its own buttons still close it, and a browser that closes the element anyway — repeated Escapes can skip cancel — finds it shown again while open stays true. |
| children | ReactNode | required | — |
DialogTrigger
Extends ComponentProps<'button'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Render your own element as the trigger instead of a bare button. |
DialogClose
Extends ComponentProps<'button'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | — |
DialogContent
Extends ComponentProps<'dialog'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| showClose | boolean | true | Corner close button. |
| dismissable | boolean | true | On DialogContent: whether a backdrop press closes the dialog. Escape still works. |
| size | 'sm' | 'default' | 'lg' | 'xl' | 'default' | Maximum width of the panel. |
| closeLabel | string | 'Close' | Accessible name for the close button. |
DialogHeader
Extends ComponentProps<'div'>.
DialogTitle
Extends ComponentProps<'h2'>.
DialogDescription
Extends ComponentProps<'p'>.
DialogBody
Extends ComponentProps<'div'>.
Behaviour
| Topic | Detail | Description |
|---|---|---|
| closed state | not-open:hidden | A display utility in className (flex, grid) used to beat the UA's display: none and leave a closed dialog drawn in the page. The closed rule is re-applied above it. |