组件
Dialog 对话框
用于展示一个对话框提示。
用法
首先从 @chakra-ui/react 导入组件。
import { Dialog } from "@chakra-ui/react"Dialog 的基本结构如下:
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.CloseTrigger />
<Dialog.Header>
<Dialog.Title />
</Dialog.Header>
<Dialog.Body />
<Dialog.Footer />
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>示例
尺寸(Sizes)
使用 size prop 来更改对话框组件的尺寸。
import {
Button,
CloseButton,
Dialog,
For,
HStack,
Portal,
} from "@chakra-ui/react"
export const DialogWithSizes = () => {
return (
<HStack>
<For each={["xs", "sm", "md", "lg"]}>
{(size) => (
<Dialog.Root key={size} size={size}>
<Dialog.Trigger asChild>
<Button variant="outline" size={size}>
Open ({size})
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)}
</For>
</HStack>
)
}覆盖(Cover)
使用 size="cover" prop 让对话框组件覆盖整个屏幕,同时露出一小部分背后的一页面内容。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithCover = () => {
return (
<Dialog.Root size="cover" placement="center" motionPreset="slide-in-bottom">
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Header>
<Dialog.Body>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</Dialog.Body>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}全屏(Fullscreen)
使用 size="full" prop 让对话框组件占据整个屏幕。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithFullscreen = () => {
return (
<Dialog.Root size="full" motionPreset="slide-in-bottom">
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}响应式尺寸
为 size prop 使用响应式值,让对话框适应不同的屏幕尺寸。
我们建议使用精确的断点值而不是 base,以确保样式被正确地区隔。
// ❌ 可能导致断点之间的样式泄漏
<Dialog.Root size={{ base: "full", md: "lg" }}>{/* ... */}</Dialog.Root>
// 可行 ✅
<Dialog.Root size={{ mdDown: "full", md: "lg" }}>{/* ... */}</Dialog.Root>import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithResponsiveSize = () => {
return (
<Dialog.Root size={{ mdDown: "full", md: "lg" }}>
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}位置(Placement)
使用 placement prop 来更改对话框组件的位置。
import {
Button,
CloseButton,
Dialog,
For,
HStack,
Portal,
} from "@chakra-ui/react"
export const DialogWithPlacement = () => {
return (
<HStack wrap="wrap" gap="4">
<For each={["top", "center", "bottom"]}>
{(placement) => (
<Dialog.Root
key={placement}
placement={placement}
motionPreset="slide-in-bottom"
>
<Dialog.Trigger asChild>
<Button variant="outline">Open Dialog ({placement}) </Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)}
</For>
</HStack>
)
}受控(Controlled)
使用 open 和 onOpenChange prop 来控制对话框组件的可见性。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
import { useState } from "react"
export const DialogControlled = () => {
const [open, setOpen] = useState(false)
return (
<Dialog.Root lazyMount open={open} onOpenChange={(e) => setOpen(e.open)}>
<Dialog.Trigger asChild>
<Button variant="outline">Open</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<p>
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}Store
控制对话框的另一种方式是使用 RootProvider 组件和 useDialog store hook。
这样就可以在对话框之外访问对话框的状态与方法。
"use client"
import {
Button,
CloseButton,
Dialog,
Portal,
useDialog,
} from "@chakra-ui/react"
export const DialogWithStore = () => {
const dialog = useDialog()
return (
<Dialog.RootProvider value={dialog}>
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
{dialog.open ? "Close" : "Open"} Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.RootProvider>
)
}Context
使用 DialogContext 组件在对话框之外访问对话框的状态与方法。
"use client"
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithContext = () => {
return (
<Dialog.Root>
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Context>
{(store) => (
<Dialog.Body pt="6" spaceY="3">
<p>Dialog is open: {store.open ? "true" : "false"}</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
</p>
<button onClick={() => store.setOpen(false)}>Close</button>
</Dialog.Body>
)}
</Dialog.Context>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}嵌套对话框
你可以在一个 Dialog.Root 中嵌套另一个 Dialog.Root 来嵌套对话框。
import { Button, Dialog, Portal } from "@chakra-ui/react"
export const DialogNested = () => {
return (
<Dialog.Root>
<Dialog.Trigger asChild>
<Button variant="outline">Open</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<p>
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</p>
</Dialog.Body>
<Dialog.Footer>
<Button variant="outline">Button 2</Button>
<Dialog.Root>
<Dialog.Trigger asChild>
<Button>Open Nested</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Sed do eiusmod tempor incididunt ut labore.
</p>
</Dialog.Body>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}从 Popover 中打开
对话框可以从 popover 内部触发。得益于统一的 z-index 系统,对话框会显示在 popover 之上。
This popover contains a button that opens a dialog. The dialog should appear above the popover.
"use client"
import {
Button,
CloseButton,
Dialog,
Popover,
Portal,
Text,
} from "@chakra-ui/react"
export const DialogOpenFromPopover = () => {
return (
<Popover.Root>
<Popover.Trigger asChild>
<Button variant="outline">Open Popover</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.Arrow />
<Popover.Body>
<Popover.Title fontWeight="medium">Popover Title</Popover.Title>
<Text my="4">
This popover contains a button that opens a dialog. The dialog
should appear above the popover.
</Text>
<PopoverDialog />
</Popover.Body>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
function PopoverDialog() {
return (
<Dialog.Root>
<Dialog.Trigger asChild>
<Button size="sm" variant="solid" colorPalette="blue">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.CloseTrigger asChild>
<CloseButton />
</Dialog.CloseTrigger>
<Dialog.Header>
<Dialog.Title>Dialog from Popover</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<Text>
This dialog was opened from within a popover. It should appear
above the popover thanks to the unified z-index system.
</Text>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button colorPalette="blue">Save</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}从菜单中打开
使用受控对话框,通过菜单项操作(例如删除确认)来打开它。
"use client"
import {
Button,
CloseButton,
Dialog,
Menu,
Portal,
Text,
} from "@chakra-ui/react"
import { useState } from "react"
import { LuChevronDown } from "react-icons/lu"
export const DialogOpenFromMenu = () => {
const [open, setOpen] = useState(false)
return (
<>
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline">
Actions <LuChevronDown />
</Button>
</Menu.Trigger>
<Portal>
<Menu.Positioner>
<Menu.Content>
<Menu.Item value="edit">Edit</Menu.Item>
<Menu.Item value="duplicate">Duplicate</Menu.Item>
<Menu.Separator />
<Menu.Item value="delete" onClick={() => setOpen(true)}>
Delete...
</Menu.Item>
</Menu.Content>
</Menu.Positioner>
</Portal>
</Menu.Root>
<Dialog.Root
role="alertdialog"
open={open}
size="sm"
onOpenChange={(e) => setOpen(e.open)}
>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.CloseTrigger asChild>
<CloseButton />
</Dialog.CloseTrigger>
<Dialog.Header>
<Dialog.Title>Confirm Delete</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<Text>
Are you sure you want to delete this item? This action cannot
be undone.
</Text>
</Dialog.Body>
<Dialog.Footer>
<Button variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button colorPalette="red">Delete</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
</>
)
}初始焦点
使用 initialFocusEl prop 来设置对话框组件的初始焦点。
"use client"
import { Button, Dialog, Field, Input, Portal, Stack } from "@chakra-ui/react"
import { useRef } from "react"
export const DialogWithInitialFocus = () => {
const ref = useRef<HTMLInputElement | null>(null)
return (
<Dialog.Root initialFocusEl={() => ref.current}>
<Dialog.Trigger asChild>
<Button variant="outline">Open</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Header</Dialog.Title>
</Dialog.Header>
<Dialog.Body pb="4">
<Stack gap="4">
<Field.Root>
<Field.Label>First Name</Field.Label>
<Input placeholder="First Name" />
</Field.Root>
<Field.Root>
<Field.Label>Last Name</Field.Label>
<Input ref={ref} placeholder="Focus First" />
</Field.Root>
</Stack>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}内部滚动
当内容溢出时,使用 scrollBehavior=inside prop 来改变对话框的滚动行为。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithInsideScroll = () => {
return (
<Dialog.Root scrollBehavior="inside" size="sm">
<Dialog.Trigger asChild>
<Button variant="outline">Inside Scroll</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>With Inside Scroll</Dialog.Title>
</Dialog.Header>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<p>
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.
</p>
<p>
Excepteur sint occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est laborum.
</p>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
accusantium doloremque laudantium, totam rem aperiam.
</p>
<p>
eaque ipsa quae ab illo inventore veritatis et quasi architecto
beatae vitae dicta sunt explicabo.
</p>
<p>
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit
aut fugit, sed quia consequuntur magni dolores eos.
</p>
<p>
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet
consectetur.
</p>
</Dialog.Body>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}外部滚动
当内容溢出时使用时 scrollBehavior=outside prop 来改变对话框的滚动行为。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithOutsideScroll = () => {
return (
<Dialog.Root size="sm" scrollBehavior="outside">
<Dialog.Trigger asChild>
<Button variant="outline">Outside Scroll</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>With Outside Scroll</Dialog.Title>
</Dialog.Header>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<p>
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.
</p>
<p>
Excepteur sint occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est laborum.
</p>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
accusantium doloremque laudantium, totam rem aperiam.
</p>
<p>
eaque ipsa quae ab illo inventore veritatis et quasi architecto
beatae vitae dicta sunt explicabo.
</p>
<p>
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit
aut fugit, sed quia consequuntur magni dolores eos.
</p>
<p>
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet
consectetur.
</p>
</Dialog.Body>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}动画预设
使用 motionPreset prop 来更改对话框组件的动画。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithMotionPreset = () => {
return (
<Dialog.Root motionPreset="slide-in-bottom">
<Dialog.Trigger asChild>
<Button variant="outline">Slide in Bottom</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}警示对话框
设置 role: "alertdialog" prop,将对话框组件变为警示对话框。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogWithRole = () => {
return (
<Dialog.Root role="alertdialog">
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Are you sure?</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
This action cannot be undone. This will permanently delete your
account and remove your data from our systems.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button colorPalette="red">Delete</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}将关闭按钮放在对话框外部
下面是一个自定义 Dialog.CloseTrigger 组件的示例,将关闭按钮定位在对话框组件之外。
import {
AspectRatio,
Button,
CloseButton,
Dialog,
Portal,
} from "@chakra-ui/react"
export const DialogWithCloseOutside = () => {
return (
<Dialog.Root placement="center">
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Body pt="4">
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description mb="4">
This is a dialog with some content and a video.
</Dialog.Description>
<AspectRatio ratio={4 / 3} rounded="lg" overflow="hidden">
<iframe
title="naruto"
src="https://www.youtube.com/embed/QhBnZ6NPOY0"
allowFullScreen
/>
</AspectRatio>
</Dialog.Body>
<Dialog.CloseTrigger top="0" insetEnd="-12" asChild>
<CloseButton bg="bg" size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}非模态对话框
由于非模态对话框带来的可用性(accessibility)问题,我们不建议使用。如果你确实需要,这里是你需要做的事情:
- 将
modalprop 设为false - 在
Dialog.Positioner组件上设置pointerEvents为none - (可选)将
closeOnInteractOutsideprop 设为false
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
export const DialogNonModal = () => {
return (
<Dialog.Root closeOnInteractOutside={false} modal={false}>
<Dialog.Trigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Positioner pointerEvents="none">
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Dialog Title</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Dialog.ActionTrigger>
<Button>Save</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}DataList 组合
这里演示了如何将对话框组件与 DataList 组件组合使用。
import {
Avatar,
Badge,
Button,
CloseButton,
DataList,
Dialog,
HStack,
Portal,
Textarea,
VStack,
} from "@chakra-ui/react"
export const DialogWithDatalist = () => {
return (
<VStack alignItems="start">
<Dialog.Root>
<Dialog.Trigger asChild>
<Button variant="outline">Open Dialog</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Prepare Chakra V3</Dialog.Title>
</Dialog.Header>
<Dialog.Body pb="8">
<DataList.Root orientation="horizontal">
<DataList.Item>
<DataList.ItemLabel>Status</DataList.ItemLabel>
<DataList.ItemValue>
<Badge colorPalette="green">Completed</Badge>
</DataList.ItemValue>
</DataList.Item>
<DataList.Item>
<DataList.ItemLabel>Assigned to</DataList.ItemLabel>
<DataList.ItemValue>
<HStack>
<Avatar.Root size="xs">
<Avatar.Image src="https://bit.ly/sage-adebayo" />
<Avatar.Fallback name="Segun Adebayo" />
</Avatar.Root>
Segun Adebayo
</HStack>
</DataList.ItemValue>
</DataList.Item>
<DataList.Item>
<DataList.ItemLabel>Due date</DataList.ItemLabel>
<DataList.ItemValue>12th August 2024</DataList.ItemValue>
</DataList.Item>
</DataList.Root>
<Textarea placeholder="Add a note" mt="8" />
</Dialog.Body>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
</VStack>
)
}Props
Root
| Prop | 默认值 | 类型 | 说明 |
|---|---|---|---|
| closeOnEscape | true | boolean | 是否在按下 Escape 键时关闭对话框。 |
| closeOnInteractOutside | true | boolean | 是否在点击外部区域时关闭对话框。 |
| lazyMount | true | boolean | 是否启用延迟挂载。 |
| modal | true | boolean | 是否禁止元素外部的指针交互,并隐藏其下方的所有内容。 |
| preventScroll | true | boolean | 是否在对话框打开时禁止其外部内容的滚动。 |
| role | 'dialog' | 'dialog' | 'alertdialog' | 对话框的 role。 |
| trapFocus | true | boolean | 是否在对话框打开时,将焦点锁定在对话框内部。 |
| unmountOnExit | true | boolean | 是否在退出时卸载组件。 |
| placement | 'top' | 'center' | 'top' | 'bottom' | 组件的位置。 |
| scrollBehavior | 'outside' | 'inside' | 'outside' | 组件的滚动行为。 |
| size | 'md' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'cover' | 'full' | 组件的尺寸。 |
| motionPreset | 'scale' | 'scale' | 'slide-in-bottom' | 'slide-in-top' | 'slide-in-left' | 'slide-in-right' | 'none' | 组件的动画预设。 |
| as | — | React.ElementType | 要渲染的底层元素。 |
| asChild | — | boolean | 使用提供的子元素作为默认渲染元素,合并它们的 props 与行为。更多详情参见我们的组合指南。 |
| unstyled | — | boolean | 是否移除组件的样式。 |
| aria-label | — | string | 对话框的可读标签;当未渲染对话框标题时使用。 |
| defaultOpen | false | boolean | 对话框渲染时的初始打开状态。当你无需控制对话框的打开状态时使用。 |
| finalFocusEl | — | () => MaybeElement | 对话框关闭时接收焦点的元素。 |
| id | — | string | 组件的唯一标识符。 |
| ids | — | Partial<{ trigger: string; positioner: string; backdrop: string; content: string; closeTrigger: string; title: string; description: string }> | 对话框内元素的 id,便于组合使用。 |
| immediate | — | boolean | 是否立即同步存在状态的变化,或将其延迟到下一帧。 |
| initialFocusEl | — | () => MaybeElement | 对话框打开时接收焦点的元素。 |
| onEscapeKeyDown | — | (event: KeyboardEvent) => void | 按下 Escape 键时调用的函数。 |
| onExitComplete | — | VoidFunction | 动画在关闭状态结束时调用的函数。 |
| onFocusOutside | — | (event: FocusOutsideEvent) => void | 焦点移动到组件外部时调用的函数。 |
| onInteractOutside | — | (event: InteractOutsideEvent) => void | 组件外部发生交互时调用的函数。 |
| onOpenChange | — | (details: OpenChangeDetails) => void | 对话框打开状态改变时调用的函数。 |
| onPointerDownOutside | — | (event: PointerDownOutsideEvent) => void | 在组件外部按下指针时调用的函数。 |
| onRequestDismiss | — | (event: LayerDismissEvent) => void | 由于父层关闭而导致本层被关闭时调用的函数。 |
| open | — | boolean | 对话框的受控打开状态。 |
| persistentElements | — | (() => Element | null)[] | 返回持久元素;这些元素不应禁用指针事件,也不应触发关闭事件。 |
| present | — | boolean | 节点是否存在(由用户控制)。 |
| restoreFocus | — | boolean | 是否将焦点恢复到打开对话框之前获得焦点的元素。 |
| skipAnimationOnMount | false | boolean | 是否允许初始的存在动画。 |