Drawer
Drawer is a panel that slides in from one of the four edges of the viewport. It can be opened and closed programmatically using its API methods open() and close(). An optional backdrop dims the content behind the drawer.
Key features:
- Slide from any edge: Drawer can slide in from
left,right,top, orbottom - Programmatic control: Open and close via exposed methods like
open(),close(), andisOpen() - Optional backdrop: Semi-transparent overlay dims content behind the drawer
- Click-away closing: Automatically close when user clicks outside the drawer
- Focus management: Automatically handles focus trapping and keyboard navigation
- Smooth animations: Configurable slide and fade animations with theme variables
Using the Component
The Drawer component is a sliding panel that appears from the edge of the viewport. It's commonly used for navigation menus, settings panels, or contextual filters.
Basic Usage with Imperative API
The simplest way to use a drawer is with the imperative API. Set an id and call open() and close() methods to control its visibility.
<App>
<VStack>
<Button label="Open Drawer" onClick="drawer.open()" />
</VStack>
<Drawer id="drawer" position="right">
<Text weight="bold" size="lg">Navigation</Text>
<VStack marginTop="$space-3">
<Button label="Profile" variant="ghost" />
<Button label="Settings" variant="ghost" />
<Button label="Help" variant="ghost" />
</VStack>
</Drawer>
</App><App>
<VStack>
<Button label="Open Drawer" onClick="drawer.open()" />
</VStack>
<Drawer id="drawer" position="right">
<Text weight="bold" size="lg">Navigation</Text>
<VStack marginTop="$space-3">
<Button label="Profile" variant="ghost" />
<Button label="Settings" variant="ghost" />
<Button label="Help" variant="ghost" />
</VStack>
</Drawer>
</App>Different Positions
Use the position property to slide the drawer from different edges of the viewport.
<App scrollWholePage="false">
<HStack>
<Button label="Right" onClick="rightDrawer.open()" />
<Button label="Bottom" onClick="bottomDrawer.open()" />
</HStack>
<SpaceFiller />
<HStack>
<SpaceFiller />
<Button label="Left" onClick="leftDrawer.open()" />
<Button label="Top" onClick="topDrawer.open()" />
</HStack>
<Drawer id="leftDrawer" position="left">
<Text>Left Drawer</Text>
</Drawer>
<Drawer id="rightDrawer" position="right">
<Text>Right Drawer</Text>
</Drawer>
<Drawer id="topDrawer" position="top">
<Text>Top Drawer</Text>
</Drawer>
<Drawer id="bottomDrawer" position="bottom">
<Text>Bottom Drawer</Text>
</Drawer>
</App><App scrollWholePage="false">
<HStack>
<Button label="Right" onClick="rightDrawer.open()" />
<Button label="Bottom" onClick="bottomDrawer.open()" />
</HStack>
<SpaceFiller />
<HStack>
<SpaceFiller />
<Button label="Left" onClick="leftDrawer.open()" />
<Button label="Top" onClick="topDrawer.open()" />
</HStack>
<Drawer id="leftDrawer" position="left">
<Text>Left Drawer</Text>
</Drawer>
<Drawer id="rightDrawer" position="right">
<Text>Right Drawer</Text>
</Drawer>
<Drawer id="topDrawer" position="top">
<Text>Top Drawer</Text>
</Drawer>
<Drawer id="bottomDrawer" position="bottom">
<Text>Bottom Drawer</Text>
</Drawer>
</App>With Backdrop Control
By default, a semi-transparent backdrop appears behind the drawer. Disable it with hasBackdrop="false" or control whether clicking the backdrop closes the drawer with closeOnClickAway.
<App>
<VStack horizontalAlignment="end">
<Button label="With Backdrop" onClick="drawer1.open()" />
<Button label="No Backdrop" onClick="drawer2.open()" />
<Button label="Click-away disabled" onClick="drawer3.open()" />
</VStack>
<Drawer id="drawer1">
<Text>Click outside to close</Text>
</Drawer>
<Drawer id="drawer2" hasBackdrop="false">
<Text>No backdrop overlay</Text>
</Drawer>
<Drawer id="drawer3" closeOnClickAway="false">
<Text>Click the close button to dismiss</Text>
</Drawer>
</App><App>
<VStack horizontalAlignment="end">
<Button label="With Backdrop" onClick="drawer1.open()" />
<Button label="No Backdrop" onClick="drawer2.open()" />
<Button label="Click-away disabled" onClick="drawer3.open()" />
</VStack>
<Drawer id="drawer1">
<Text>Click outside to close</Text>
</Drawer>
<Drawer id="drawer2" hasBackdrop="false">
<Text>No backdrop overlay</Text>
</Drawer>
<Drawer id="drawer3" closeOnClickAway="false">
<Text>Click the close button to dismiss</Text>
</Drawer>
</App>Drawer with Events
Monitor when the drawer opens or closes using onOpen and onClose events.
<App var.openCount="{0}" var.closeCount="{0}">
<VStack>
<Button label="Open Drawer" onClick="drawer.open()" />
<Text>Opened: {openCount} times</Text>
<Text>Closed: {closeCount} times</Text>
</VStack>
<Drawer
id="drawer"
position="right"
onOpen="openCount++"
onClose="closeCount++">
<Text>I track my open/close events</Text>
</Drawer>
</App><App var.openCount="{0}" var.closeCount="{0}">
<VStack>
<Button label="Open Drawer" onClick="drawer.open()" />
<Text>Opened: {openCount} times</Text>
<Text>Closed: {closeCount} times</Text>
</VStack>
<Drawer
id="drawer"
position="right"
onOpen="openCount++"
onClose="closeCount++">
<Text>I track my open/close events</Text>
</Drawer>
</App>Behaviors
This component supports the following behaviors:
| Behavior | Properties |
|---|---|
| Animation | animation, animationOptions |
| Bookmark | bookmark, bookmarkLevel, bookmarkTitle, bookmarkOmitFromToc |
| Component Label | label, labelPosition, labelWidth, labelBreak, required, enabled, shrinkToLabel, style, readOnly |
| Publish/Subscribe | subscribeToTopic |
| Tooltip | tooltip, tooltipMarkdown, tooltipOptions |
| Styling Variant | variant |
Properties
closeButtonVisible
default: true
When true, an ✕ button is displayed in the top-right corner of the drawer that closes it when clicked.
Controls whether the close (✕) button appears in the top-right corner of the drawer.
<App>
<VStack horizontalAlignment="end">
<Button label="With Close Button (default)" onClick="drawer1.open()" />
<Button label="Without Close Button" onClick="drawer2.open()" />
</VStack>
<Drawer id="drawer1" closeButtonVisible="true">
<Text>Close button visible</Text>
</Drawer>
<Drawer id="drawer2" closeButtonVisible="false">
<Text>No close button, click outside to dismiss</Text>
</Drawer>
</App><App>
<VStack horizontalAlignment="end">
<Button label="With Close Button (default)" onClick="drawer1.open()" />
<Button label="Without Close Button" onClick="drawer2.open()" />
</VStack>
<Drawer id="drawer1" closeButtonVisible="true">
<Text>Close button visible</Text>
</Drawer>
<Drawer id="drawer2" closeButtonVisible="false">
<Text>No close button, click outside to dismiss</Text>
</Drawer>
</App>closeOnClickAway
default: true
When true, clicking outside the drawer panel closes it.
hasBackdrop
default: true
When true, a translucent overlay is shown behind the drawer while it is open.
initiallyOpen
default: false
When true, the drawer is open on its first render.
position
default: "left"
Specifies the edge from which the drawer slides in.
Available values: left (default), right, top, bottom
Events
close
Fired when the Drawer is closed.
Fired when the drawer closes (via API, close button, backdrop click, or Escape key).
<App var.status="">
<VStack>
<Button label="Open Drawer" onClick="drawer.open()" />
<Text>{status}</Text>
</VStack>
<Drawer
id="drawer"
position="right"
onClose="status = 'Drawer closed at ' + formatDateTime(getDate())">
<Text>I triggered the onClose event</Text>
</Drawer>
</App><App var.status="">
<VStack>
<Button label="Open Drawer" onClick="drawer.open()" />
<Text>{status}</Text>
</VStack>
<Drawer
id="drawer"
position="right"
onClose="status = 'Drawer closed at ' + formatDateTime(getDate())">
<Text>I triggered the onClose event</Text>
</Drawer>
</App>open
Fired when the Drawer is opened.
Fired when the drawer opens (either via open() API or another trigger).
<App var.status="">
<VStack >
<Button label="Open Drawer" onClick="drawer.open()" />
<Text>{status}</Text>
</VStack>
<Drawer
id="drawer"
position="right"
onOpen="status = 'Drawer opened at ' + formatDateTime(getDate())">
<Text>I triggered the onOpen event</Text>
</Drawer>
</App><App var.status="">
<VStack >
<Button label="Open Drawer" onClick="drawer.open()" />
<Text>{status}</Text>
</VStack>
<Drawer
id="drawer"
position="right"
onOpen="status = 'Drawer opened at ' + formatDateTime(getDate())">
<Text>I triggered the onOpen event</Text>
</Drawer>
</App>Exposed Methods
close
Closes the Drawer. Invoke with drawerId.close().
Signature: close(): void
isOpen
Returns true when the Drawer is currently open, false otherwise.
Signature: isOpen(): boolean
open
Opens the Drawer. Invoke with drawerId.open().
Signature: open(): void
Styling
Theme Variables
| Variable | Default Value (Light) | Default Value (Dark) |
|---|---|---|
| animationDuration-Drawer | 250ms | 250ms |
| animationEasing-Drawer | cubic-bezier(0.4, 0, 0.2, 1) | cubic-bezier(0.4, 0, 0.2, 1) |
| backgroundColor-backdrop-Drawer | rgba(0, 0, 0, 0.4) | rgba(0, 0, 0, 0.4) |
| backgroundColor-Drawer | $backgroundColor-primary | $backgroundColor-primary |
| borderRadius-Drawer | $borderRadius | $borderRadius |
| boxShadow-Drawer | 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05) | 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05) |
| height-Drawer | 320px | 320px |
| maxHeight-Drawer | 50% | 50% |
| maxWidth-Drawer | 80% | 80% |
| padding-Drawer | $space-4 | $space-4 |
| width-Drawer | 320px | 320px |
| zIndex-Drawer | 200 | 200 |