Component
Dialog
A modal window above a scrim, in five widths. Focus moves into it when it opens and goes back to the trigger when it closes. It uses shadow-high, the shadow kept for floating layers.
Xem trước
import { Button } from "@/components/ui/button"
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>Cách dùng
Khi nào dùng
- A short task that should block the page until it is done or cancelled, such as renaming a project.
- A confirmation that is not destructive.
- A task that needs room, such as a table or a preview, with a larger size.
Khi nào không dùng
- Confirming a destructive action. Use AlertDialog.
- Long forms or reading. Give them their own page.
- Opening a dialog from a dialog. Close the first one before the next one opens, or give the flow its own page.
Biến thể
size
Set on DialogContent. Widest the panel gets: sm 448px (short confirmations), md 512px (forms of a few fields), lg 672px, xl 896px (tables, previews), full the whole viewport minus spacing-lg on each side, in height too. On a narrow screen every size fills the width minus spacing-lg.
import { Button } from "@/components/ui/button"
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent size="lg">
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent size="xl">
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent size="full">
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>Ví dụ
Default
import { Button } from "@/components/ui/button"
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
<DialogDescription>Pick a name your team will recognize.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>Nên và không nên
Nên
- Use a dialog for a short task or a confirmation that should block the page until done or cancelled.
- Pick the smallest size that fits the content: sm for a sentence and two buttons, md for a short form, lg or xl for tables and previews. Long content scrolls inside the panel, which stays spacing-lg from the viewport edges.
- Let Escape, the close button and a scrim click close it.
- Open and close without animation (current behavior). If an animation is added later, reduced motion gets a fade only.
- Return focus to the trigger on close.
Không nên
- Don't use Dialog to confirm a destructive action. Use AlertDialog, which focuses Cancel first and doesn't close on a scrim click.
- Don't open a dialog from a dialog.
- Don't use a dialog for long forms or reading; use a page or sheet. A bigger size does not make a long form short.
- Don't use size full for a short task; the user loses sight of the page they came from.
- Don't leave out DialogTitle. If it shouldn't show, make it sr-only.
- Don't remove shadow-high from the panel. A dialog floats above the page, so a border alone isn't enough.
Props
| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
|---|---|---|---|---|
| open | boolean | - | - | Set on Dialog. Whether the dialog is open, when you control it. Pair it with onOpenChange. Chỉ trên web. |
| defaultOpen | boolean | - | false | Set on Dialog. Opens the dialog on first render, when you don't control it. Chỉ trên web. |
| onOpenChange | function | - | - | Set on Dialog. Called with true or false when the dialog opens or closes (trigger, close button, Escape, scrim). Chỉ trên web. |
| modal | boolean | - | true | Set on Dialog. true traps focus and hides the rest of the page from assistive tech. Keep it true; false only for a panel the user works next to, which is better as a sheet. Chỉ trên web. |
| size | enum | sm | md | lg | xl | full | md | Set on DialogContent. Widest the panel gets: sm 448px (short confirmations), md 512px (forms of a few fields), lg 672px, xl 896px (tables, previews), full the whole viewport minus spacing-lg on each side, in height too. On a narrow screen every size fills the width minus spacing-lg. |
| showCloseButton | boolean | - | true | DialogContent: show the corner close button. DialogFooter takes the same prop (default false) to add a secondary Close button. Chỉ trên web. |
Slot
| Tên | Bắt buộc | Mô tả |
|---|---|---|
| trigger | không | Element that opens the dialog. |
| title | có | Dialog title (required for a11y). |
| description | không | Optional supporting text. |
| content | không | Main body. |
| footer | không | Actions. |
Cấu tạo
| Phần | Mô tả |
|---|---|
| root | Root. Controls open state. |
| overlay | Scrim behind the content. color-overlay-scrim. |
| content | The floating panel: raised surface, radius-page, shadow-high, border. |
| header | Top block for title and description. |
| title | Accessible name of the dialog. |
| description | Optional supporting text. |
| footer | Actions row at the bottom. |
| close | Icon button that dismisses the dialog. |
| icon | Tabler XIcon inside the close control, 16px. |
| hitArea | Transparent ::before on the close control, never smaller than size-target-min. |
Khả năng truy cập
Role: dialog
| Phím | Hành động |
|---|---|
| Escape | Closes the dialog and returns focus to the trigger. |
| Tab | Cycles focus inside the dialog (focus trap). |
- Traps focus and closes on Escape. Hides the rest of the page from assistive tech (aria-hidden on siblings); it does not set aria-modal.
- Always provide a DialogTitle (visible or sr-only) so the dialog has an accessible name.
- The corner close is a DialogClose with an sr-only "Close" label and a Tabler XIcon. If showCloseButton is false on DialogContent, the footer must have a Cancel or Close.
- Do not nest dialogs.
Cài đặt
npx shadcn add https://werewolf-ui.vercel.app/r/dialog.jsonLệnh này thêm luôn styles/werewolf.css, bộ token mà mọi component dùng, và các component khác mà nó cần. Import file đó một lần trong CSS gốc, ngay sau @import "tailwindcss", với đường dẫn tính từ file CSS đó (từ app/globals.css là @import "../styles/werewolf.css").