Drawer
Drawer slides a panel in from an edge of the screen over a dimmed page: details beside a list, filters, a thread, or a phone’s navigation menu. It has two parts: Drawer is the layer and the sliding panel, and DrawerContent lays out a title, a body that scrolls on its own and a footer inside it.
It is the same kind of floating layer as Modal: it stacks with the z-index manager, so a Select, Popover or Modal opened inside it shows above it, and Escape closes the innermost layer first. While it is open, focus stays inside, the page behind is hidden from assistive tech and does not scroll, and focus returns to whatever opened it when it closes.
Demos
Basic
show and onUpdateShow control it; it comes from the right by default. DrawerContent’s title names the drawer, closable adds ×, and footer pins a row below the body.
Placement
placement picks the edge: top, right, bottom or left. A top or bottom drawer spans the screen’s width.
Navigation menu
A left drawer is the menu of a narrow layout, as on this site on a phone. Pick a page and the menu closes.
Long content
The title and the footer stay put; the body scrolls between them with ScrollArea. nativeScrollbar uses the browser’s own scrollbar instead.
Resizable
resizable makes the inner edge a handle: drag it, or focus it and use the arrow keys. minWidth / maxWidth (minHeight / maxHeight for top and bottom) bound it, and onUpdateWidth / onUpdateHeight report the new size.
Mask
showMask="transparent" keeps an invisible mask that still catches the closing click. showMask={false} draws none: the page stays usable and focus is not trapped (turn off blockScroll too to let it scroll). A click on the page still closes the drawer unless maskClosable is off.
Drawer Props
| Name | Type | Default | Description | Version |
|---|---|---|---|---|
show | boolean | undefined | Controlled visibility. | Unreleased |
defaultShow | boolean | false | Initial visibility when uncontrolled. | Unreleased |
onUpdateShow | (show: boolean) => void | undefined | Called with the new visibility whenever the drawer wants to open or close. | Unreleased |
children | ReactNode | undefined | The panel: usually a DrawerContent. | Unreleased |
placement | 'top' | 'right' | 'bottom' | 'left' | 'right' | The edge it slides in from. | Unreleased |
width | number | string | undefined | Controlled width of a left / right drawer; a number is in px. The theme’s default is 360px. | Unreleased |
defaultWidth | number | string | undefined | Initial width when uncontrolled. | Unreleased |
onUpdateWidth | (width: number) => void | undefined | Called with the new width in px while resizing. | Unreleased |
height | number | string | undefined | Controlled height of a top / bottom drawer; a number is in px. The theme’s default is 320px. | Unreleased |
defaultHeight | number | string | undefined | Initial height when uncontrolled. | Unreleased |
onUpdateHeight | (height: number) => void | undefined | Called with the new height in px while resizing. | Unreleased |
resizable | boolean | false | Drag the inner edge (or use the arrow keys on it) to resize. | Unreleased |
minWidth / maxWidth | number | undefined | Width bounds in px when resizing. | Unreleased |
minHeight / maxHeight | number | undefined | Height bounds in px when resizing. | Unreleased |
showMask | boolean | 'transparent' | true | Dim the page, keep an invisible mask, or draw none and leave the page usable. | Unreleased |
maskClosable | boolean | true | Close on a click on the mask (or the page, without a mask). | Unreleased |
onMaskClick | (event: MouseEvent) => void | undefined | Called on a click on the mask, whether or not it closes. | Unreleased |
closeOnEsc | boolean | true | Close on Escape. | Unreleased |
onEsc | () => void | undefined | Called on Escape, whether or not it closes. | Unreleased |
autoFocus | boolean | true | Focus the first focusable element inside on open; off focuses the drawer itself. | Unreleased |
trapFocus | boolean | true | Keep Tab inside and hide the page from assistive tech (aria-modal). Only with a mask. | Unreleased |
blockScroll | boolean | true | Stop the page from scrolling while open. | Unreleased |
displayDirective | 'if' | 'show' | 'if' | Unmount when closed, or keep the DOM, hidden. | Unreleased |
to | string | HTMLElement | false | undefined | Where to mount; false renders in place. Defaults to ConfigProvider’s portalContainer, then document.body. | Unreleased |
zIndex | number | undefined | A fixed z-index instead of stacking above the layers opened before it. | Unreleased |
onAfterEnter | () => void | undefined | Called when the enter animation has finished. | Unreleased |
onAfterLeave | () => void | undefined | Called when the leave animation has finished. | Unreleased |
Other props, className, style and ref go to the drawer element (role="dialog"). The drawer never grows past the screen, keeps clear of the notch and the home indicator on the edges it touches, and with reduced motion only fades.
DrawerContent Props
| Name | Type | Default | Description | Version |
|---|---|---|---|---|
title | ReactNode | undefined | The heading; it also names the drawer. | Unreleased |
children | ReactNode | undefined | The body. Taller content scrolls between the title and the footer. | Unreleased |
footer | ReactNode | undefined | A row pinned below the body. | Unreleased |
closable | boolean | false | Show the × button. | Unreleased |
onClose | () => boolean | void | Promise<boolean | void> | undefined | Called by ×. false keeps it open. | Unreleased |
nativeScrollbar | boolean | false | Scroll the body with the browser’s scrollbar instead of ScrollArea. | Unreleased |
Other props, className, style and ref go to the content’s root element. DrawerContent must be inside a Drawer.