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
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
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
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
Pass the offset
prop to the DrawerContent
to change 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
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
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.
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.
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.
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 |
---|---|---|
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 |
contained | 'true' | 'false' The contained of the component | |
as | React.ElementType The underlying element to render. | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | boolean Whether to remove the component's style. |