Components
Dialog
A modal dialog for confirmations, forms, and focused tasks. Includes backdrop, keyboard dismissal, and focus trapping.
Basic usage
Compose with DialogTrigger, DialogContent, DialogHeader, and DialogFooter. Pass asChild to the trigger so it renders a real Button.
Controlled
Pass open and onOpenChange for full control.
Sizes
size is a Comitor addition to the shadcn dialog. It maps to a static sm:max-w-* class so Tailwind can see it at build time; on narrow viewports every size falls back to max-w-[calc(100%-2rem)].
With form
DialogBody is the second Comitor addition: the region between header and footer that owns the scroll, so a long form never pushes the title or the actions out of view. Give it max-h-* only when you want a cap tighter than the dialog's own — the scrolling itself is already built in.
Close button
The corner ✕ is on by default. Turn it off with showCloseButton={false} when the footer should be the only exit, and keep at least one DialogClose in reach. When you keep it, set closeLabel — its default screen-reader text is the Vietnamese "Đóng".
Dialog Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. Pair with onOpenChange. |
defaultOpen | boolean | false | Open state on first render, for uncontrolled usage. |
onOpenChange | (open: boolean) => void | — | Called whenever the dialog opens or closes. |
modal | boolean | true | When true, content outside the dialog is inert and hidden from assistive technology. |
childrenrequired | React.ReactNode | — | Dialog trigger and content. |
DialogContent Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Max width from the sm breakpoint up (sm:max-w-sm … sm:max-w-xl). Below sm the panel is always max-w-[calc(100%-2rem)]. Package addition — not in the shadcn baseline. |
showCloseButton | boolean | true | Render the ✕ button in the top-right corner of the panel. |
closeLabel | string | 'Đóng' | Visually hidden label on that close button. The package default is Vietnamese — pass an English string in an English UI. |
className | string | — | Merged onto the panel with cn(); use it for one-off width or padding overrides. |
…Radix Content | DialogPrimitive.ContentProps | — | Everything else is forwarded to Radix Dialog.Content — onEscapeKeyDown, onInteractOutside, onOpenAutoFocus, forceMount. |
Parts
Every part accepts className, which is merged onto the defaults with cn().
| Prop | Type | Default | Description |
|---|---|---|---|
Dialog | DialogPrimitive.Root | — | Stateful container. Holds the open state and the trigger/content pair. |
DialogTrigger | DialogPrimitive.Trigger | — | Control that opens the dialog. Use asChild to render your own Button. |
DialogPortal | DialogPrimitive.Portal | — | Portal target. DialogContent already renders one — reach for it only when building a custom content shell. |
DialogOverlay | DialogPrimitive.Overlay | — | Dimmed backdrop (bg-ink/60, dark:bg-ink/80, backdrop-blur). Also rendered for you by DialogContent. |
DialogContent | DialogPrimitive.Content | — | The centred panel: portal + overlay + card surface + optional close button. |
DialogHeader | div | — | flex flex-col gap-2, centred on mobile and left-aligned from sm up. |
DialogBody | div | — | Scrolling content region between header and footer — the package applies -m-1 min-h-0 flex-auto overflow-y-auto p-1, so the header and footer stay pinned and the focus ring on a w-full child is not clipped. Package addition. |
DialogFooter | div | — | Actions row: stacked and reversed on mobile, right-aligned from sm up. |
DialogTitle | DialogPrimitive.Title | — | Accessible name for the panel. Always include one. |
DialogDescription | DialogPrimitive.Description | — | Supporting text wired to aria-describedby. |
DialogClose | DialogPrimitive.Close | — | Dismisses the dialog. Use asChild to wrap your own Button. |
Accessibility
- Built on Radix Dialog: the panel carries
role="dialog"andaria-modal="true", focus is trapped while open and returns to the trigger on close. - Always include a
DialogTitle— it suppliesaria-labelledby;DialogDescriptionsuppliesaria-describedby. - Escape and a click on the backdrop both close the dialog. Intercept them with
onEscapeKeyDown/onInteractOutsidewhen there is unsaved work — or reach forAlertDialog, which refuses outside clicks by design. - Body scroll is locked and the rest of the page is inert while
modalis true. - The corner close button has no visible text — its accessible name comes from the visually hidden
closeLabel, which defaults to"Đóng". PasscloseLabel="Close"in English interfaces.