Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

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.

  • npm: 3 trực tiếp, 5 tổng
  • registry: 3 trực tiếp, 3 tổng

Xem trước

Props

  • open
  • defaultOpen
  • size
  • showCloseButton
  • title
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.

  • sm

  • mdmặc định

  • lg

  • xl

  • full

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ênKiểuGiá trịMặc địnhMô tả
openboolean--Đặ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.
defaultOpenboolean-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.
onOpenChangefunction--Đặ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.
modalboolean-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.
sizeenumsm | md | lg | xl | fullmdĐặ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.
showCloseButtonboolean-trueDialogContent: 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ênBắt buộcMô tả
triggerkhôngPhần tử mở dialog.
titlecóTiêu đề dialog (bắt buộc cho a11y).
descriptionkhôngChữ hỗ trợ, tùy chọn.
contentkhôngPhần thân chính.
footerkhôngCác hành động.

Cấu tạo

PhầnMô tả
rootRoot. Điều khiển trạng thái mở.
overlayScrim phía sau nội dung. color-overlay-scrim.
contentPanel nổi: bề mặt raised, radius-page, shadow-high, viền.
headerKhối trên cho title và description.
titleTên truy cập của dialog.
descriptionChữ hỗ trợ tùy chọn.
footerHàng hành động ở dưới.
closeButton icon để đóng dialog.
iconTabler 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ímHành động
EscapeĐóng dialog và trả focus về trigger.
TabXoay 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 dialog

Chạ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.