Skip to main content
PolyUI/docs

浮层组件

对话框

带遮罩的模态对话框,支持键盘导航(Esc 关闭)和焦点陷阱,完全符合 WAI-ARIA 规范。

安装

bash
pnpm dlx shadcn@latest add dialog -c packages/react

基础用法

tsx
import {
  Dialog, DialogContent, DialogHeader,
  DialogTitle, DialogDescription, DialogFooter
} from "@polyui/react/dialog"
import { Button } from "@polyui/react/button"

export function DeleteConfirm() {
  return (
    <Dialog>
      <Button>打开对话框</Button>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>确认删除</DialogTitle>
          <DialogDescription>
            此操作不可撤销,数据将永久删除。
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <Button variant="outline">取消</Button>
          <Button variant="destructive">删除</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

受控模式

通过 open 和 onOpenChange 完全控制对话框的开关状态。

tsx
const [open, setOpen] = useState(false)

<Dialog open={open} onOpenChange={setOpen}>
  <Button onClick={() => setOpen(true)}>
    打开
  </Button>
  <DialogContent>
    {/* ... */}
  </DialogContent>
</Dialog>

基础

Basic Dialogs

vue
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from "@polyui/vue/dialog"
import { Button } from "@polyui/vue/button"
export function DialogBasicDemos() {
  return (
    <div class="flex flex-wrap gap-3">
      <Dialog>
        <DialogTrigger as-child>
          <Button variant="outline">Basic Dialog</Button>
        </DialogTrigger>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Are you absolutely sure?</DialogTitle>
            <DialogDescription>
              This action cannot be undone. This will permanently delete your account and remove your data from our
              servers.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <DialogClose as-child>
              <Button variant="outline">Cancel</Button>
            </DialogClose>
            <Button>Continue</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog>
        <DialogTrigger as-child>
          <Button variant="outline">Destructive</Button>
        </DialogTrigger>
        <DialogContent>
          <DialogHeader class="items-center">
            <DialogTitle>Are you absolutely sure?</DialogTitle>
            <DialogDescription class="text-center">
              This action cannot be undone. This will permanently delete your account and remove your data from our
              servers.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <DialogClose as-child>
              <Button variant="outline">Cancel</Button>
            </DialogClose>
            <Button variant="destructive">Delete</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog>
        <DialogTrigger as-child>
          <Button variant="outline">Edit Profile</Button>
        </DialogTrigger>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Edit profile</DialogTitle>
            <DialogDescription>Make changes to your profile here. Click save when you're done.</DialogDescription>
          </DialogHeader>
          <div class="grid gap-4">
            <div class="grid gap-2">
              <label for="dlg-name-vue">Name</label>
              <input id="dlg-name-vue" value="Pedro Duarte" class="border rounded px-3 py-2 text-sm" />
            </div>
            <div class="grid gap-2">
              <label for="dlg-username-vue">Username</label>
              <input id="dlg-username-vue" value="@peduarte" class="border rounded px-3 py-2 text-sm" />
            </div>
          </div>
          <DialogFooter>
            <DialogClose as-child>
              <Button variant="outline">Cancel</Button>
            </DialogClose>
            <Button type="submit">Save changes</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog>
        <DialogTrigger as-child>
          <Button variant="outline">Terms &amp; Conditions</Button>
        </DialogTrigger>
        <DialogContent class="sm:max-w-md">
          <DialogHeader>
            <DialogTitle class="border-b pb-3">Terms and Conditions</DialogTitle>
          </DialogHeader>
          <div class="text-muted-foreground py-2 text-sm">
            <ol class="flex list-decimal flex-col gap-2 pl-4">
              <li>
                <strong class="text-foreground">Eligibility:</strong> You must be at least 18 years old to use this
                service.
              </li>
              <li>
                <strong class="text-foreground">Account Responsibility:</strong> You are responsible for maintaining the
                confidentiality of your account and password.
              </li>
              <li>
                <strong class="text-foreground">Usage:</strong> Do not misuse or attempt to disrupt the service.
              </li>
              <li>
                <strong class="text-foreground">Data Collection:</strong> We collect and use your data as described in
                our Privacy Policy.
              </li>
              <li>
                <strong class="text-foreground">Modifications:</strong> We reserve the right to update or modify these
                terms at any time.
              </li>
            </ol>
          </div>
          <DialogFooter>
            <DialogClose as-child>
              <Button variant="outline">Cancel</Button>
            </DialogClose>
            <DialogClose as-child>
              <Button>I Agree</Button>
            </DialogClose>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  )
}

富内容

Rich Content

tsx
export function DialogRichContent() {
  return (
    <div className="flex flex-col gap-3">
      <p className="text-xs font-mono text-muted-foreground tracking-widest uppercase">Rich Content</p>
      <div className="flex flex-wrap gap-3">
        <DialogReferAndEarn />
        <DialogRating />
        <DialogSignInV2 />
        <DialogSignUpV2 />
        <DialogInviteV2 />
      </div>
    </div>
  )
}

定位

Positioning

tsx
export function DialogPositioning() {
  return (
    <div className="flex flex-col gap-3">
      <p className="text-xs font-mono text-muted-foreground tracking-widest uppercase">Positioning</p>
      <div className="flex flex-wrap gap-3">
        <DialogTopLeft />
        <DialogTop />
        <DialogTopRight />
        <DialogMiddleLeft />
        <DialogMiddleRight />
        <DialogBottomLeft />
        <DialogBottom />
        <DialogBottomRight />
      </div>
    </div>
  )
}

动画

Animations

tsx
export function DialogAnimations() {
  return (
    <div className="flex flex-col gap-3">
      <p className="text-xs font-mono text-muted-foreground tracking-widest uppercase">Animations</p>
      <div className="flex flex-wrap gap-3">
        <DialogSlideToTop />
        <DialogSlideToRight />
        <DialogZoomIn />
      </div>
    </div>
  )
}

Props

Dialog

属性类型默认值说明
openboolean受控开关状态
onOpenChange(open: boolean) => void状态变化回调
defaultOpenbooleanfalse非受控初始状态
modalbooleantrue是否为模态(阻止背景交互)

DialogContent

属性类型默认值说明
classNamestring自定义样式
showCloseButtonbooleantrue是否显示右上角关闭按钮
onEscapeKeyDown(e: KeyboardEvent) => voidEsc 键回调
onPointerDownOutside(e: PointerEvent) => void点击遮罩回调