<Dialog>
<Button>Open Drawer</Button>
<Drawer>
<DialogContent>
<DialogHeader>
<DialogTitle>Drawer Title</DialogTitle>
<DialogDescription>This is a drawer description.</DialogDescription>
</DialogHeader>
<DialogBody>
<p>Drawer content goes here.</p>
</DialogBody>
<DialogFooter>
<Button slot="close">Close</Button>
</DialogFooter>
</DialogContent>
</Drawer>
</Dialog>Installation
npx shadcn@latest add @dotui/drawerUsage
Use drawers to display content that slides in from the edge of the screen.
import { Button } from '@/components/ui/button'
import { Dialog, DialogContent } from '@/components/ui/dialog'
import { Drawer } from '@/components/ui/drawer'<Dialog>
<Button>Open Drawer</Button>
<Drawer placement="bottom">
<DialogContent>Drawer content</DialogContent>
</Drawer>
</Dialog>Anatomy
A Drawer has no built-in trigger. Wrap it in a Dialog with a Button child as the trigger, and put your content inside DialogContent.
import { Button } from '@/components/ui/button'
import { Dialog, DialogContent } from '@/components/ui/dialog'
import {
Drawer,
DrawerHandle,
DrawerSwipeArea,
DrawerProvider,
DrawerIndent,
DrawerIndentBackground,
} from '@/components/ui/drawer'
;<Dialog>
<Button />
<Drawer>
<DialogContent>
<DrawerHandle />
</DialogContent>
</Drawer>
</Dialog>DrawerHandle is a visible drag affordance. DrawerSwipeArea is an edge region that opens the drawer by swiping. DrawerIndent and DrawerIndentBackground wrap page content that scales and translates behind an open drawer, and DrawerProvider scopes visual state explicitly — most apps don't need it.
Open state
Rendered under a Dialog, the drawer shares the dialog's open state, so the trigger Button opens it with no wiring. To drive it yourself, pass isOpen with onOpenChange (or defaultOpen for uncontrolled).
const [isOpen, setIsOpen] = React.useState(false)
<Drawer isOpen={isOpen} onOpenChange={setIsOpen}>
<DialogContent>...</DialogContent>
</Drawer>Dismissal
The drawer dismisses on swipe, outside interaction, and Escape. Disable each with swipeToDismiss, isDismissable, and isKeyboardDismissDisabled respectively.
<Drawer swipeToDismiss={false} isDismissable={false} isKeyboardDismissDisabled>
<DialogContent>...</DialogContent>
</Drawer>Examples
Basic Drawer
Settings Panel
Nested Drawers
Scrollable Content
Form Drawer
API Reference
Drawer
A React Aria compatible drawer overlay powered by Base UI's Drawer overlay primitives.
| Prop | Type | Default | |
|---|---|---|---|
DrawerPlacement | 'bottom' | ||
boolean | true | ||
boolean | true | ||
boolean | false | ||
ReactNode | — | ||
DrawerHandle
DrawerSwipeArea
An edge region that can open the drawer by swiping.
| Prop | Type | Default | |
|---|---|---|---|
boolean | false | ||
SwipeDirection | — | ||
DrawerProvider
Optional explicit visual-state scope. Most apps don't need this.
DrawerIndent
Wraps page content; scales/translates while a drawer is open.
| Prop | Type | Default | |
|---|---|---|---|
DrawerIndentBackground
The dark layer behind the indented content.
| Prop | Type | Default | |
|---|---|---|---|
Last updated on 7/7/2026