'use client';
import { Button } from '#components/ui/button'
import { Drawer } from '#components/ui/drawer'
export const DrawerBasic = () => {
return (
<Drawer.Root>
<Drawer.Backdrop />
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseButton />
</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>
<Drawer.ActionTrigger asChild>
<Button variant="ghost">Cancel</Button>
</Drawer.ActionTrigger>
<Button variant="glass" colorPalette="accent">
Save
</Button>
</Drawer.Footer>
<Drawer.CloseTrigger />
</Drawer.Content>
</Drawer.Root>
)
}
Anatomy
import { Drawer } from '#components/ui/drawer'<Drawer.Root>
<Drawer.Backdrop />
<Drawer.Trigger />
<Drawer.Content>
<Drawer.Header>
<Drawer.Title />
<Drawer.CloseButton />
</Drawer.Header>
<Drawer.Body />
<Drawer.Footer>
<Drawer.CloseTrigger asChild>
<Button>Close</Button>
</Drawer.CloseTrigger>
</Drawer.Footer>
</Drawer.Content>
</Drawer.Root>Examples
Attached
Use the attached prop to render the drawer to attach to the edge of the viewport.
'use client';
import { useState } from 'react'
import { Button } from '#components/ui/button'
import { Drawer } from '#components/ui/drawer'
export const DrawerAttached = () => {
const [open, setOpen] = useState(false)
return (
<Drawer.Root open={open} onOpenChange={(e) => setOpen(e.open)} attached>
<Drawer.Backdrop />
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseButton />
</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>
<Drawer.ActionTrigger asChild>
<Button variant="ghost">Cancel</Button>
</Drawer.ActionTrigger>
<Button variant="glass" colorPalette="accent">
Save
</Button>
</Drawer.Footer>
</Drawer.Content>
</Drawer.Root>
)
}
Sizes
Use the size prop to change the size of the drawer component.
'use client'
import { For, HStack, Kbd } from '@chakra-ui/react'
import { Button } from '#components/ui/button'
import { Drawer } from '#components/ui/drawer'
export const DrawerWithSizes = () => {
return (
<HStack wrap="wrap">
<For each={['xs', 'sm', 'md', 'lg', 'xl', 'full']}>
{(size) => (
<Drawer.Root key={size} size={size}>
<Drawer.Backdrop />
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open ({size})
</Button>
</Drawer.Trigger>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseButton />
</Drawer.Header>
<Drawer.Body>
Press the <Kbd>esc</Kbd> key to close the drawer.
</Drawer.Body>
<Drawer.Footer>
<Drawer.ActionTrigger asChild>
<Button variant="ghost">Cancel</Button>
</Drawer.ActionTrigger>
<Button variant="glass" colorPalette="accent">
Save
</Button>
</Drawer.Footer>
</Drawer.Content>
</Drawer.Root>
)}
</For>
</HStack>
)
}
Offset
Pass the offset prop to the DrawerContent to change the offset of the drawer
component.
'use client';
import { Button } from '#components/ui/button'
import { Drawer } from '#components/ui/drawer'
export const DrawerWithOffset = () => {
return (
<Drawer.Root>
<Drawer.Backdrop />
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Drawer.Content offset="4" rounded="md">
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseButton />
</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>
<Drawer.ActionTrigger asChild>
<Button variant="ghost">Cancel</Button>
</Drawer.ActionTrigger>
<Button variant="glass" colorPalette="accent">
Save
</Button>
</Drawer.Footer>
<Drawer.CloseTrigger />
</Drawer.Content>
</Drawer.Root>
)
}
Placement
Use the placement prop to change the placement of the drawer component.
'use client'
import { For, HStack } from '@chakra-ui/react'
import { Button } from '#components/ui/button'
import { Drawer } from '#components/ui/drawer'
export const DrawerWithPlacement = () => {
return (
<HStack wrap="wrap">
<For each={['bottom', 'top', 'start', 'end']}>
{(placement) => (
<Drawer.Root key={placement} placement={placement}>
<Drawer.Backdrop />
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open ({placement})
</Button>
</Drawer.Trigger>
<Drawer.Content
roundedTop={placement === 'bottom' ? 'l3' : undefined}
roundedBottom={placement === 'top' ? 'l3' : undefined}
>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseButton />
</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="ghost">Cancel</Button>
</Drawer.ActionTrigger>
<Button variant="glass" colorPalette="accent">
Save
</Button>
</Drawer.Footer>
</Drawer.Content>
</Drawer.Root>
)}
</For>
</HStack>
)
}
Initial Focus
Use the initialFocusEl prop to set the initial focus of the drawer component.
'use client'
import { useRef } from 'react'
import { Input, Stack } from '@chakra-ui/react'
import { Button } from '#components/ui/button'
import { Drawer } from '#components/ui/drawer'
export const DrawerWithInitialFocus = () => {
const ref = useRef<HTMLInputElement>(null)
return (
<Drawer.Root initialFocusEl={() => ref.current}>
<Drawer.Backdrop />
<Drawer.Trigger asChild>
<Button variant="outline" size="sm">
Open Drawer
</Button>
</Drawer.Trigger>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
<Drawer.CloseButton />
</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>
<Drawer.ActionTrigger asChild>
<Button variant="ghost">Cancel</Button>
</Drawer.ActionTrigger>
<Button variant="glass" colorPalette="accent">
Save
</Button>
</Drawer.Footer>
</Drawer.Content>
</Drawer.Root>
)
}
Props
Root
| Prop | Default | Type |
|---|---|---|
closeOnEscape | true | booleanWhether to close the drawer when the escape key is pressed. |
closeOnInteractOutside | true | booleanWhether to close the drawer when the outside is clicked. |
closeThreshold | '0.25' | numberThe threshold distance for dismissing the drawer. |
hideMode | ''display-none'' | HideModeHow to hide content when mounted but not present. - `'display-none'`: HTML `hidden` attribute. Effects stay alive. - `'activity'`: React 19 `<Activity mode="hidden">`. Effects pause. Requires React 19+. |
lazyMount | false | booleanWhether to enable lazy mounting |
modal | true | booleanWhether to prevent pointer interaction outside the element and hide all content below it. |
preventDragOnScroll | true | booleanWhether to prevent dragging on scrollable elements. When enabled, the sheet will not start dragging if the user is interacting with a scrollable element. |
preventScroll | true | booleanWhether to prevent scrolling behind the sheet when it's opened |
restoreFocus | true | booleanWhether to restore focus to the element that had focus before the sheet was opened. |
role | '\'dialog\'' | 'dialog' | 'alertdialog'The sheet's role |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
snapPoints | '[1]' | SnapPoint[]The snap points of the drawer. Array of numbers or strings representing the snap points. |
snapToSequentialPoints | false | booleanWhether the drawer should snap to sequential points when swiping. |
swipeDirection | '\'down\'' | SwipeDirectionThe direction in which the drawer can be swiped. |
swipeVelocityThreshold | '700' | numberThe threshold velocity (in pixels/s) for closing the drawer. |
trapFocus | true | booleanWhether to trap focus inside the sheet when it's opened. |
unmountOnExit | false | booleanWhether to unmount on exit. |
colorPalette | 'gray' | 'gray' | 'zinc' | 'neutral' | 'stone' | 'red' | 'orange' | 'amber' | 'yellow' | 'lime' | 'green' | 'emerald' | 'teal' | 'cyan' | 'sky' | 'blue' | 'indigo' | 'violet' | 'purple' | 'fuchsia' | 'pink' | 'rose' | 'presence' | 'status' | 'sidebar' | 'sidebar.accent' | 'accent' | 'slate'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 |
defaultOpen | booleanThe initial open state of the drawer. | |
defaultSnapPoint | SnapPoint | |
defaultTriggerValue | stringThe default trigger value (uncontrolled). | |
finalFocusEl | () => MaybeElementElement to receive focus when the sheet is closed. | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{
backdrop: string
positioner: string
content: string
title: string
description: string
header: string
trigger: string | ((value?: string | undefined) => string)
grabber: string
grabberIndicator: string
closeTrigger: string
swipeArea: string
}>The ids of the elements in the drawer. 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 sheet 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 called when the open state changes. | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
onRequestDismiss | (event: LayerDismissEvent) => voidFunction called when this layer is closed due to a parent layer being closed | |
onSnapPointChange | (details: SnapPointChangeDetails) => voidCallback fired when the snap point changes. | |
onTriggerValueChange | (details: TriggerValueChangeDetails) => voidCallback when the active trigger value changes. | |
open | booleanWhether the drawer is open. | |
present | booleanWhether the node is present (controlled by the user) | |
snapPoint | SnapPointThe currently active snap point. | |
stack | DrawerStackOptional external store for coordinating app-level drawer stack visuals (e.g. indent and background layers). | |
triggerValue | stringThe value of the trigger that currently controls the drawer. | |
attached | 'true' | 'false'The attached 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. |