import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react"
const Demo = () => {
return (
<Drawer.Root>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Drawer.Body>
<Drawer.Footer>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
用法
¥Usage
import { Drawer } from "@chakra-ui/react"
<Drawer.Root>
<Drawer.Backdrop />
<Drawer.Trigger />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.CloseTrigger />
<Drawer.Header>
<Drawer.Title />
</Drawer.Header>
<Drawer.Body />
<Drawer.Footer />
</Drawer.Content>
</Drawer.Positioner>
</Drawer.Root>
示例
¥Examples
受控
¥Controlled
使用 open 和 onOpenChange 属性控制抽屉组件。
¥Use the open and onOpenChange props to control the drawer component.
"use client"
import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react"
import { useState } from "react"
const Demo = () => {
const [open, setOpen] = useState(false)
return (
<Drawer.Root open={open} onOpenChange={(e) => setOpen(e.open)}>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Drawer.Body>
<Drawer.Footer>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
尺寸
¥Sizes
使用 size 属性更改抽屉组件的大小。
¥Use the size prop to change the size of the drawer component.
import {
Button,
CloseButton,
Drawer,
For,
HStack,
Kbd,
Portal,
} from "@chakra-ui/react"
const Demo = () => {
return (
<HStack wrap="wrap">
<For each={["xs", "sm", "md", "lg", "xl", "full"]}>
{(size) => (
<Drawer.Root key={size} size={size}>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open ({size})
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
Press the <Kbd>esc</Kbd> key to close the drawer.
</Drawer.Body>
<Drawer.Footer>
<Drawer.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Drawer.ActionTrigger>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)}
</For>
</HStack>
)
}
上下文
¥Context
使用 DrawerContext 组件从抽屉外部访问抽屉状态和方法。
¥Use the DrawerContext component to access the drawer state and methods from
outside the drawer.
"use client"
import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react"
const Demo = () => {
return (
<Drawer.Root>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Context>
{(store) => (
<Drawer.Body pt="6" spaceY="3">
<p>Drawer 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>
</Drawer.Body>
)}
</Drawer.Context>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
偏移
¥Offset
在 Drawer.Positioner 上使用 padding CSS 属性来调整抽屉组件的偏移量。
¥Use the padding CSS property on Drawer.Positioner to adjust the offset of
the drawer component.
import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react"
const Demo = () => {
return (
<Drawer.Root>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner padding="4">
<Drawer.Content rounded="md">
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Drawer.Body>
<Drawer.Footer>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
放置位置
¥Placement
使用 placement 属性更改抽屉组件的位置。
¥Use the placement prop to change the placement of the drawer component.
import {
Button,
CloseButton,
Drawer,
For,
HStack,
Portal,
} from "@chakra-ui/react"
const Demo = () => {
return (
<HStack wrap="wrap">
<For each={["bottom", "top", "start", "end"]}>
{(placement) => (
<Drawer.Root key={placement} placement={placement}>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open ({placement})
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content
roundedTop={placement === "bottom" ? "l3" : undefined}
roundedBottom={placement === "top" ? "l3" : undefined}
>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
</Drawer.Body>
<Drawer.Footer>
<Drawer.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Drawer.ActionTrigger>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)}
</For>
</HStack>
)
}
初始焦点
¥Initial Focus
使用 initialFocusEl 属性设置抽屉组件的初始焦点。
¥Use the initialFocusEl prop to set the initial focus of the drawer component.
"use client"
import {
Button,
CloseButton,
Drawer,
Input,
Portal,
Stack,
} from "@chakra-ui/react"
import { useRef } from "react"
const Demo = () => {
const ref = useRef<HTMLInputElement>(null)
return (
<Drawer.Root initialFocusEl={() => ref.current}>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<Stack mt="5">
<Input defaultValue="Naruto" placeholder="First name" />
<Input ref={ref} placeholder="Email" />
</Stack>
</Drawer.Body>
<Drawer.Footer>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
自定义容器
¥Custom Container
以下是如何在自定义容器中渲染抽屉组件的示例。
¥Here's an example of how to render the drawer component in a custom container.
考虑将 closeOnInteractOutside 设置为 false,以防止抽屉在与外部交互时关闭。
¥Consider setting closeOnInteractOutside to false to prevent the drawer from
closing when interacting outside the drawer.
Render drawer here
"use client"
import {
Button,
CloseButton,
Drawer,
Portal,
Stack,
type StackProps,
Text,
} from "@chakra-ui/react"
import { forwardRef, useRef } from "react"
const DrawerContainer = forwardRef<HTMLDivElement, StackProps>(
function DrawerContainer(props, ref) {
return (
<Stack
pos="relative"
overflow="hidden"
align="flex-start"
p="8"
minH="400px"
layerStyle="fill.subtle"
outline="2px solid gray"
ref={ref}
{...props}
/>
)
},
)
const Demo = () => {
const portalRef = useRef<HTMLDivElement | null>(null)
return (
<Drawer.Root closeOnInteractOutside={false}>
<DrawerContainer ref={portalRef}>
<Text>Render drawer here</Text>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm" bg="bg">
Open Drawer
</Button>
</Drawer.Trigger>
</DrawerContainer>
<Portal container={portalRef}>
<Drawer.Backdrop pos="absolute" boxSize="full" />
<Drawer.Positioner pos="absolute" boxSize="full">
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Header>
<Drawer.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Drawer.Body>
<Drawer.Footer>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</Drawer.Footer>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
标题操作
¥Header Actions
以下是在抽屉组件标题中渲染操作的示例。
¥Here's an example of rendering actions in the header of the drawer component.
import {
Button,
ButtonGroup,
CloseButton,
Drawer,
Portal,
} from "@chakra-ui/react"
const Demo = () => {
return (
<Drawer.Root size="md">
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Header>
<Drawer.CloseTrigger asChild pos="initial">
<CloseButton />
</Drawer.CloseTrigger>
<Drawer.Title flex="1">Drawer Title</Drawer.Title>
<ButtonGroup>
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</ButtonGroup>
</Drawer.Header>
<Drawer.Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Drawer.Body>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
)
}
带条件变量的抽屉
¥Drawer with conditional variants
以下是如何根据不同断点更改变体的示例。
¥Here is an example of how to change variants based on the different breakpoints.
本示例使用 mdDown 断点更改抽屉在小屏幕上的位置。推荐使用此方法,因为两种条件都会转换为 CSS 媒体查询,从而避免基础样式合并问题。
¥This example uses the mdDown breakpoint to change the drawer's placement on
smaller screens. This approach is recommended because both conditions are
translated into CSS media queries, which helps avoid base style merging issues.
如果你确实想使用基本条件,则还需要定义相应的大小。例如:<Drawer.Root placement={{ base: "bottom", md: "end" }} size={{ base: "xs", md: "md" }}>
¥If you really want to use the base condition instead, you’ll also need to define
corresponding sizes. For example:
<Drawer.Root placement={{ base: "bottom", md: "end" }} size={{ base: "xs", md: "md" }}>
Open drawer and resize screen to mobile size
import {
Button,
CloseButton,
Drawer,
Kbd,
Portal,
Text,
} from "@chakra-ui/react"
const Demo = () => {
return (
<>
<Text mb="4">Open drawer and resize screen to mobile size</Text>
<Drawer.Root placement={{ mdDown: "bottom", md: "end" }}>
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Portal>
<Drawer.Backdrop />
<Drawer.Positioner>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>
Press the <Kbd>esc</Kbd> key to close the drawer.
</Drawer.Body>
<Drawer.Footer>
<Drawer.ActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</Drawer.ActionTrigger>
<Button>Save</Button>
</Drawer.Footer>
<Drawer.CloseTrigger asChild>
<CloseButton size="sm" />
</Drawer.CloseTrigger>
</Drawer.Content>
</Drawer.Positioner>
</Portal>
</Drawer.Root>
</>
)
}
属性
¥Props
根元素
¥Root
| Prop | Default | Type |
|---|---|---|
closeOnEscape | true | booleanWhether to close the dialog when the escape key is pressed |
closeOnInteractOutside | true | booleanWhether to close the dialog when the outside is clicked |
defaultOpen | false | booleanThe initial open state of the dialog when rendered. Use when you don't need to control the open state of the dialog. |
lazyMount | false | booleanWhether to enable lazy mounting |
modal | true | booleanWhether to prevent pointer interaction outside the element and hide all content below it |
preventScroll | true | booleanWhether to prevent scrolling behind the dialog when it's opened |
role | '\'dialog\'' | 'dialog' | 'alertdialog'The dialog's role |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
trapFocus | true | booleanWhether to trap focus inside the dialog when it's opened |
unmountOnExit | false | booleanWhether to unmount on exit. |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink'The color palette of the component |
size | 'xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'The size of the component |
placement | 'end' | 'start' | 'end' | 'top' | 'bottom'The placement of the component |
as | React.ElementTypeThe underlying element to render. | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | booleanWhether to remove the component's style. | |
aria-label | stringHuman readable label for the dialog, in event the dialog title is not rendered | |
finalFocusEl | () => MaybeElementElement to receive focus when the dialog is closed | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{
trigger: string
positioner: string
backdrop: string
content: string
closeTrigger: string
title: string
description: string
}>The ids of the elements in the dialog. Useful for composition. | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
initialFocusEl | () => MaybeElementElement to receive focus when the dialog is opened | |
onEscapeKeyDown | (event: KeyboardEvent) => voidFunction called when the escape key is pressed | |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
onOpenChange | (details: OpenChangeDetails) => voidFunction to call when the dialog's open state changes | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
open | booleanThe controlled open state of the dialog | |
persistentElements | (() => Element | null)[]Returns the persistent elements that: - should not have pointer-events disabled - should not trigger the dismiss event | |
present | booleanWhether the node is present (controlled by the user) | |
restoreFocus | booleanWhether to restore focus to the element that had focus before the dialog was opened | |
contained | 'true' | 'false'The contained of the component |