import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
return (
<Dialog.Root>
<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>
)
}
用法
import { Dialog } from "@chakra-ui/react"
<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>
示例
尺寸
使用 size
属性来改变对话框组件的尺寸。
import {
Button,
CloseButton,
Dialog,
For,
HStack,
Portal,
} from "@chakra-ui/react"
const Demo = () => {
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>
)
}
覆盖
使用 size="cover"
属性使对话框组件覆盖整个屏幕,同时显示页面背面的一小部分。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
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>
)
}
全屏
使用 size="full"
属性使对话框组件占据整个屏幕。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
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>
)
}
位置
使用 placement
属性来改变对话框组件的位置。
import {
Button,
CloseButton,
Dialog,
For,
HStack,
Portal,
} from "@chakra-ui/react"
const Demo = () => {
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>
)
}
受控
使用 open
和 onOpenChange
属性来控制对话框组件的可见性。
"use client"
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
import { useState } from "react"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
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>
<Lorem p={2} />
</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>
)
}
存储
控制对话框的另一种方式是使用 RootProvider
组件和 useDialog
存储钩子。
这样,您就可以从对话框外部访问对话框的状态和方法。
"use client"
import {
Button,
CloseButton,
Dialog,
Portal,
useDialog,
} from "@chakra-ui/react"
const Demo = () => {
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>
)
}
上下文
使用 DialogContext
组件从对话框外部访问对话框的状态和方法。
"use client"
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
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>
)
}
初始焦点
使用 initialFocusEl
属性设置对话框组件的初始焦点。
"use client"
import { Button, Dialog, Field, Input, Portal, Stack } from "@chakra-ui/react"
import { useRef } from "react"
const Demo = () => {
const ref = useRef<HTMLInputElement>(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
属性改变对话框内容溢出时的滚动行为。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
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>
<Lorem p={8} />
</Dialog.Body>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}
外部滚动
使用 scrollBehavior=outside
属性改变对话框内容溢出时的滚动行为。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
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>
<Lorem p={8} />
</Dialog.Body>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}
运动预设
使用 motionPreset
属性改变对话框组件的动画。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
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"
属性将对话框组件更改为警报对话框。
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
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"
const Demo = () => {
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>
)
}
非模态对话框
由于可访问性问题,我们不建议使用非模态对话框。如果您确实需要,可以这样做:
- 将
modal
属性设置为false
- 将
pointerEvents
在Dialog.Positioner
组件上设置为none
- (可选)将
closeOnInteractOutside
属性设置为false
import { Button, CloseButton, Dialog, Portal } from "@chakra-ui/react"
const Demo = () => {
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"
const Demo = () => {
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>
)
}
属性
根
属性 | 默认值 | 类型 |
---|---|---|
closeOnEscape | true | boolean 按下 Esc 键时是否关闭对话框 |
closeOnInteractOutside | true | boolean 点击外部时是否关闭对话框 |
lazyMount | false | boolean 是否启用懒挂载 |
modal | true | boolean 是否阻止元素外部的指针交互并隐藏其下方所有内容 |
preventScroll | true | boolean 对话框打开时是否阻止其背景滚动 |
role | '\''dialog'\'' | 'dialog' | 'alertdialog' 对话框的角色 |
trapFocus | true | boolean 对话框打开时是否将焦点限制在对话框内部 |
unmountOnExit | false | boolean 退出时是否卸载。 |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink' 组件的颜色调色板 |
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' 组件的运动预设 |
aria-label | string 对话框的可读标签,以防对话框标题未渲染 | |
defaultOpen | boolean 对话框首次渲染时的初始打开状态。在您不需要控制其打开状态时使用。 | |
finalFocusEl | () => HTMLElement | null 对话框关闭时接收焦点的元素 | |
id | string 机器的唯一标识符。 | |
ids | Partial<{ trigger: string positioner: string backdrop: string content: string closeTrigger: string title: string description: string }> 对话框中元素的 ID。对于组合很有用。 | |
immediate | boolean 是否立即同步当前更改或将其推迟到下一帧 | |
initialFocusEl | () => HTMLElement | null 对话框打开时接收焦点的元素 | |
onEscapeKeyDown | (event: KeyboardEvent) => void 按下 Esc 键时调用的函数 | |
onExitComplete | () => void 动画在关闭状态下结束时调用的函数 | |
onFocusOutside | (event: FocusOutsideEvent) => void 焦点移出组件时调用的函数 | |
onInteractOutside | (event: InteractOutsideEvent) => void 组件外部发生交互时调用的函数 | |
onOpenChange | (details: OpenChangeDetails) => void 对话框打开或关闭时调用的回调函数 | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void 指针在组件外部按下时调用的函数 | |
open | boolean 对话框是否打开 | |
persistentElements | (() => Element | null)[] 返回持久元素,这些元素: - 不应禁用指针事件 - 不应触发关闭事件 | |
present | boolean 节点是否显示(由用户控制) | |
restoreFocus | boolean 对话框打开前是否将焦点恢复到之前获得焦点的元素 | |
as | React.ElementType 要渲染的基础元素。 | |
asChild | ||
unstyled | boolean 是否移除组件的样式。 |