Drawer

Organism
A full-screen panel that slides in from an edge: a navigation drawer, a mobile menu, or a bottom action sheet. Built on React Native's Modal, so it floats over the whole app on iOS, Android, and the web, over a dimmed scrim that glass on the web also blurs. For a small contextual menu, reach for Dropdown or RowMenu instead.

Playground

Every control sets a real prop of DrawerProps. The JSX below updates as you go.
Props
Edge
pick one
navigation
boolean
plain
boolean
JSX · DrawerProps
<Drawer right />

Variants

4 examples from src/organisms/drawer/drawer.md, each rendered live from its own JSX.
Application panel
<Drawer plain instant right width={440} trigger="Agent details" header={<Typography h3 bold>Scout</Typography>} footer={<Button secondary>Pause</Button>}>
<Typography>Recent work and trace details.</Typography>
</Drawer>
Right
<Drawer trigger="Right drawer" right>
<Column padLoose snug>
<Typography lead semibold>Details</Typography>
<Typography small muted>A full-height panel on the right.</Typography>
</Column>
</Drawer>
Bottom sheet
<Drawer trigger="Bottom sheet" bottom>
<Column padLoose snug>
<Typography lead semibold>Actions</Typography>
<Typography small muted>A sheet that rises from the bottom edge.</Typography>
</Column>
</Drawer>
Top sheet
<Drawer trigger="Top sheet" top>
<Column padLoose snug>
<Typography lead semibold>What's new</Typography>
<Typography small muted>A sheet that drops down from the top edge.</Typography>
</Column>
</Drawer>

Anatomy

1
Scrim
2
Panel
3
Header
4
Body
5
Footer
Dimmed parts appear only in some states or variants.

Props

18 props on DrawerProps, grouped as they are declared in source. Required props are marked *.
Prop
Type
Default
Description
Props
10 props
header
ReactNode
–
Pinned header above the independently scrolling body.
footer
ReactNode
–
Pinned actions below the independently scrolling body.
navigation
boolean
false
Navigation body: no content inset or inter-item gap; fills the available height.
plain
boolean
false
Square web side panel and the original lightly frosted application dim.
instant
boolean
false
Present and dismiss immediately, preserving the original application interaction.
embedded
boolean
false
Show the open drawer as a non-modal specimen inside its parent, for a catalogue or a showcase: the panel docks against its edge of the parent (which gives it its height) over the dim, with no Modal, no slide, no focus trap, and no close on Escape, native back or a tap on the dim. It keeps its labelling as a named region. Ignored with trigger, which always opens a live drawer.
children
ReactNode
–
Panel content.
open
boolean
false
Controlled open state. Omit for uncontrolled (a trigger opens it).
onOpenChange
(open: boolean) => void
–
Fired when the open state changes (trigger press, scrim tap, back/escape).
trigger
string
–
Label for an optional outline trigger button. When set, the drawer renders the button and opens itself on press (uncontrolled). Omit when you drive open yourself.
Edge axis
pick one
8 props
left
boolean
false
A full-height panel on the left edge (default).
right
boolean
false
A full-height panel on the right edge.
bottom
boolean
false
A sheet spanning the width, rising from the bottom.
top
boolean
false
A sheet spanning the width, dropping from the top.
width
number
300
Width of a side drawer in px (default 300). Ignored for the bottom/top sheet.
accessibilityLabel
string
–
Accessible name for the modal surface. Required when the drawer has no trigger whose label can name it.
testID
string
–
E2E hook forwarded to the root element.
style
StyleProp<ViewStyle>
–
Outer layout composition for the panel surface, never a restyle hook. (Device safe-area insets are applied automatically.)

Accessibility and keyboard

Keyboard
Tab
Shift+Tab
Cycles focus inside the panel
Escape
Closes when dismissible
Enter
Confirms in forms
Semantics
Roles
region
ARIA on web
aria-label
From the docs
On iOS, VoiceOver's accessibility escape gesture requests dismissal of the foremost open child before the drawer. Android system back uses the same child ownership. A controlled child that stays open continues to own later requests; one request never falls through to its parent. The scrim remains a pointer target, and the built-in trigger opens the drawer. Sidebar drill-down navigation has its own back behavior; accessibility escape dismisses the overlay rather than navigating a sidebar level. Focus restoration rem
Give a controlled drawer an accessibilityLabel when it has no built-in trigger. A drawer with a trigger uses the trigger label as its modal name.

Platform skins

The playground's props on each platform: same tree, native shapes, type and touch sizes.
Web
control 10 · field 10 · card 16 · Instrument Sans
iOS
capsule controls · field 8 · card 12 · SF Pro · 44 pt
Android
Material 3 stadium · field 4 · card 12 · Roboto · 48 dp

Usage

<Drawer trigger="Open menu">
<Column padLoose cozy>
<Typography lead semibold>Menu</Typography>
<Button ghost block>Home</Button>
<Button ghost block>Components</Button>
<Button ghost block>Settings</Button>
</Column>
</Drawer>
Drawer provides an overlay host inside its own window. Dropdown, Select, and other anchored children render above the panel without being clipped by its corners; no additional OverlayProvider is needed inside the drawer. A tap outside an open child menu dismisses that menu, and Escape dismisses the child before the drawer. Nested drawers each keep their overlays in their own window.
On iOS, VoiceOver's accessibility escape gesture requests dismissal of the foremost open child before the drawer. Android system back uses the same child ownership. A controlled child that stays open continues to own later requests; one request never falls through to its parent. The scrim remains a pointer target, and the built-in trigger opens the drawer. Sidebar drill-down navigation has its own back behavior; accessibility escape dismisses the overlay rather than navigating a sidebar level. Focus restoration remains platform-dependent.
Give a controlled drawer an accessibilityLabel when it has no built-in trigger. A drawer with a trigger uses the trigger label as its modal name.

Tokens

Read from the playground render. Values follow the scheme and the ion hue.
--bf
--bg2
--bls
--bw
--f-dp
--fd
--ft
--gl
--ion
--ion-fg
--ln
--ln2
--scrim
--sf3
--sh-lg
--tx
--tx3

Related components