Component
Dialog
Cửa sổ modal nằm trên scrim, với năm bề rộng. Focus đi vào nó khi mở và trở về trigger khi đóng. Nó dùng shadow-high, bóng giữ cho các lớp nổi.
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>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>Cách dùng
Khi nào dùng
- Việc ngắn cần chặn trang cho đến khi xong hoặc bị hủy, chẳng hạn đổi tên một dự án.
- Xác nhận không phải hành động destructive.
- Việc cần chỗ, chẳng hạn một bảng hoặc một bản xem trước, với size lớn hơn.
Khi nào không dùng
- Xác nhận hành động destructive. Dùng AlertDialog.
- Form dài hoặc nội dung để đọc. Cho chúng một trang riêng.
- Mở một dialog từ một dialog. Đóng cái đầu trước khi cái sau mở, hoặc cho luồng đó một trang riêng.
Biến thể
size
Đặt trên DialogContent. Bề rộng tối đa của panel: sm 448px (xác nhận ngắn), md 512px (form vài field), lg 672px, xl 896px (bảng, bản xem trước), full là cả viewport trừ spacing-lg mỗi bên, chiều cao cũng vậy. Trên màn hình hẹp, mọi size phủ kín chiều ngang trừ 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>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent size="lg">
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent size="xl">
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent size="full">
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>Ví dụ
Mặc định
import { Button } from "@/components/ui/button"
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
<Dialog>
<DialogTrigger asChild>
<Button>Đổi tên dự án</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Đổi tên dự án</DialogTitle>
<DialogDescription>Chọn một tên mà nhóm của bạn sẽ nhận ra.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Hủy</Button>
</DialogClose>
<Button>Lưu</Button>
</DialogFooter>
</DialogContent>
</Dialog>Nên và không nên
Nên
- Dùng dialog cho việc ngắn hoặc xác nhận cần chặn trang cho đến khi xong hoặc hủy.
- Chọn size nhỏ nhất vừa nội dung: sm cho một câu và hai button, md cho form ngắn, lg hoặc xl cho bảng và bản xem trước. Nội dung dài cuộn trong panel, và panel cách mép viewport một khoảng spacing-lg.
- Để Escape, button đóng và một lần nhấn scrim đóng nó.
- Để nó mờ dần và scale khi vào (duration-slow, ease-enter) và khi ra thì nhanh hơn (duration-fast, ease-exit). Khi giảm chuyển động, nó chỉ mờ dần. Command palette mở từ bàn phím nhiều lần mỗi ngày thì mở và đóng ngay.
- Trả focus về trigger khi đóng.
Không nên
- Đừng dùng Dialog để xác nhận hành động destructive. Dùng AlertDialog, nó focus vào Cancel trước và không đóng khi nhấn scrim.
- Đừng mở một dialog từ một dialog.
- Đừng dùng dialog cho form dài hoặc để đọc; dùng một trang hoặc sheet. Size lớn hơn không làm form dài thành ngắn.
- Đừng dùng size full cho việc ngắn; người dùng mất tầm nhìn trang họ vừa rời.
- Đừng bỏ DialogTitle. Nếu nó không nên hiện, đặt nó là sr-only.
- Đừng bỏ shadow-high khỏi panel. Dialog nổi trên trang, nên chỉ một viền là không đủ.
Props
| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
|---|---|---|---|---|
| open | boolean | - | - | Đặt trên Dialog. Dialog có đang mở hay không, khi bạn kiểm soát nó. Ghép với onOpenChange. Chỉ trên web. |
| defaultOpen | boolean | - | false | Đặt trên Dialog. Mở dialog ở lần render đầu, khi bạn không kiểm soát nó. Chỉ trên web. |
| onOpenChange | function | - | - | Đặt trên Dialog. Được gọi với true hoặc false khi dialog mở hoặc đóng (trigger, button đóng, Escape, scrim). Chỉ trên web. |
| modal | boolean | - | true | Đặt trên Dialog. true giữ focus bên trong và ẩn phần còn lại của trang khỏi công nghệ hỗ trợ. Giữ nó là true; false chỉ cho panel mà người dùng làm việc ngay cạnh, lúc đó nên dùng Sheet. Chỉ trên web. |
| size | enum | sm | md | lg | xl | full | md | Đặt trên DialogContent. Bề rộng tối đa của panel: sm 448px (xác nhận ngắn), md 512px (form vài field), lg 672px, xl 896px (bảng, bản xem trước), full là cả viewport trừ spacing-lg mỗi bên, chiều cao cũng vậy. Trên màn hình hẹp, mọi size phủ kín chiều ngang trừ spacing-lg. |
| showCloseButton | boolean | - | true | DialogContent: hiện button đóng ở góc. DialogFooter nhận cùng prop (mặc định false) để thêm một button Close phụ. Chỉ trên web. |
Slot
| Tên | Bắt buộc | Mô tả |
|---|---|---|
| trigger | không | Phần tử mở dialog. |
| title | có | Tiêu đề dialog (bắt buộc cho a11y). |
| description | không | Chữ hỗ trợ, tùy chọn. |
| content | không | Phần thân chính. |
| footer | không | Các hành động. |
Cấu tạo
| Phần | Mô tả |
|---|---|
| root | Root. Điều khiển trạng thái mở. |
| overlay | Scrim phía sau nội dung. color-overlay-scrim. |
| content | Panel nổi: bề mặt raised, radius-page, shadow-high, viền. |
| header | Khối trên cho title và description. |
| title | Tên truy cập của dialog. |
| description | Chữ hỗ trợ tùy chọn. |
| footer | Hàng hành động ở dưới. |
| close | Button icon để đóng dialog. |
| icon | Tabler XIcon trong control đóng, 16px. |
| hitArea | ::before trong suốt trên control đóng, không bao giờ nhỏ hơn size-target-min. |
Khả năng truy cập
Role: dialog
| Phím | Hành động |
|---|---|
| Escape | Đóng dialog và trả focus về trigger. |
| Tab | Xoay focus bên trong dialog (focus trap). |
- Giữ focus bên trong và đóng khi Escape. Ẩn phần còn lại của trang khỏi công nghệ hỗ trợ (aria-hidden trên các phần tử anh em); nó không đặt aria-modal.
- Luôn có DialogTitle (nhìn thấy hoặc sr-only) để dialog có tên truy cập.
- Nút đóng ở góc là một DialogClose với nhãn sr-only "Close" và một Tabler XIcon. Nếu showCloseButton là false trên DialogContent, footer phải có Cancel hoặc Close.
- Đừng lồng các dialog.
Cài đặt
npx werewolf-ui add dialogChạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.