Skip to content

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.

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

NameTypeDefaultDescriptionVersion
showbooleanundefinedControlled visibility.Unreleased
defaultShowbooleanfalseInitial visibility when uncontrolled.Unreleased
onUpdateShow(show: boolean) => voidundefinedCalled with the new visibility whenever the drawer wants to open or close.Unreleased
childrenReactNodeundefinedThe panel: usually a DrawerContent.Unreleased
placement'top' | 'right' | 'bottom' | 'left''right'The edge it slides in from.Unreleased
widthnumber | stringundefinedControlled width of a left / right drawer; a number is in px. The theme’s default is 360px.Unreleased
defaultWidthnumber | stringundefinedInitial width when uncontrolled.Unreleased
onUpdateWidth(width: number) => voidundefinedCalled with the new width in px while resizing.Unreleased
heightnumber | stringundefinedControlled height of a top / bottom drawer; a number is in px. The theme’s default is 320px.Unreleased
defaultHeightnumber | stringundefinedInitial height when uncontrolled.Unreleased
onUpdateHeight(height: number) => voidundefinedCalled with the new height in px while resizing.Unreleased
resizablebooleanfalseDrag the inner edge (or use the arrow keys on it) to resize.Unreleased
minWidth / maxWidthnumberundefinedWidth bounds in px when resizing.Unreleased
minHeight / maxHeightnumberundefinedHeight bounds in px when resizing.Unreleased
showMaskboolean | 'transparent'trueDim the page, keep an invisible mask, or draw none and leave the page usable.Unreleased
maskClosablebooleantrueClose on a click on the mask (or the page, without a mask).Unreleased
onMaskClick(event: MouseEvent) => voidundefinedCalled on a click on the mask, whether or not it closes.Unreleased
closeOnEscbooleantrueClose on Escape.Unreleased
onEsc() => voidundefinedCalled on Escape, whether or not it closes.Unreleased
autoFocusbooleantrueFocus the first focusable element inside on open; off focuses the drawer itself.Unreleased
trapFocusbooleantrueKeep Tab inside and hide the page from assistive tech (aria-modal). Only with a mask.Unreleased
blockScrollbooleantrueStop the page from scrolling while open.Unreleased
displayDirective'if' | 'show''if'Unmount when closed, or keep the DOM, hidden.Unreleased
tostring | HTMLElement | falseundefinedWhere to mount; false renders in place. Defaults to ConfigProvider’s portalContainer, then document.body.Unreleased
zIndexnumberundefinedA fixed z-index instead of stacking above the layers opened before it.Unreleased
onAfterEnter() => voidundefinedCalled when the enter animation has finished.Unreleased
onAfterLeave() => voidundefinedCalled 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

NameTypeDefaultDescriptionVersion
titleReactNodeundefinedThe heading; it also names the drawer.Unreleased
childrenReactNodeundefinedThe body. Taller content scrolls between the title and the footer.Unreleased
footerReactNodeundefinedA row pinned below the body.Unreleased
closablebooleanfalseShow the × button.Unreleased
onClose() => boolean | void | Promise<boolean | void>undefinedCalled by ×. false keeps it open.Unreleased
nativeScrollbarbooleanfalseScroll 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.