Trang này chưa có bản tiếng Việt. Nội dung dưới đây là bản tiếng Anh.
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 — the way a dialog opens from a menu item, a table row or a keyboard shortcut. The button below only sets state; it is not a DialogTrigger, and closing still puts focus back on it: since 3.3.0, DialogContent returns focus to whatever had it when the dialog opened.
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, its screen-reader name is closeLabel: “Close” by default, “Đóng” under a Vietnamese ComitorLocaleProvider, and your own string when you pass one — worth doing when “Close” alone would not say which panel goes.
Dialog Props
| Prop | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
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. |
childrenbắt buộc | React.ReactNode | — | Dialog trigger and content. |
DialogContent Props
| Prop | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
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 | 'Close' | Visually hidden label on that close button. Follows ComitorLocaleProvider — “Đóng” under locale="vi" — and a value passed here wins, e.g. 'Close invoice preview' when “Close” alone would not say which panel goes. |
className | string | — | Merged onto the panel with cn(); use it for one-off width or padding overrides. |
onCloseAutoFocus | (event: Event) => void | — | Runs as the dialog closes, before focus moves — ahead of both Radix and the package's own focus return, so it wins: call event.preventDefault() and focus what should come next. Keep one that sends focus somewhere else, such as the next row after a delete; one that only re-focused the opener can go, since DialogContent does that itself (see Accessibility). |
…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 | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
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", and focus is trapped while it is open. - On close, focus returns to the
DialogTrigger— or, with no Trigger, to the element that had focus just before the dialog opened: the button that setopen, a table row, anActionBaraction. Radix only covers the Trigger; the rest is the package’s, since 3.3.0 — before it, a dialog opened from state dropped focus on<body>(WCAG 2.4.3). Since 3.3.1 a field withautoFocusinside the dialog no longer defeats it. - Opened from a
DropdownMenuitem, which unmounts with the menu, focus goes to the menu’s trigger button — out of submenus, to the root one. The package acts only when focus has really been lost, and it never guesses: when the opener is gone, say the row the dialog just deleted, nothing is focused. That is the job foronCloseAutoFocus, which runs first and wins once it callsevent.preventDefault(). - Not covered: content kept mounted with
forceMount, which records the opener only when Radix runs its open auto-focus, and Drawer, which is vaul’s. Return focus yourself inonCloseAutoFocusthere. - 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 is “Close” by default and follows the language of the nearestComitorLocaleProvider. Pass your own when the page needs something more specific.