Drawer

A panel that slides in from any edge, with swipe to dismiss, snap points and an indented page behind it.

React

Examples

Basic

A bottom drawer with a grabber. Drag it down or press Escape to close it.

Swipe direction

Set placement to start, end, top or bottom to choose the edge the drawer slides in from. Drawer.Root turns it into Zag's swipeDirection, so the drawer swipes back toward the same edge. start and end follow the text direction: turn on right-to-left in the preview toolbar and they swap sides.

Float

Set float to float the drawer inside the viewport, with a gap from the edge and rounded corners on every side. It works with every swipe direction.

Snap points

snapPoints lists the heights the drawer can rest at, as fractions of the viewport or as lengths like "20rem". defaultSnapPoint picks where it opens. A snap point never exceeds the content size, so give the content a height when you snap to a fraction. The content gets data-expanded at its full height, which this example uses to let the list scroll only then.

Set modal, trapFocus, preventScroll and closeOnInteractOutside to false to keep the page usable while the drawer is open. Leave out Drawer.Backdrop so it doesn't cover the page.

Controlled

Pass open and onOpenChange to open and close the drawer from outside and follow its state. Anything that sets the state opens or closes it, so it needs no Drawer.Trigger.

Scrollable

Long content scrolls inside Drawer.Body, so the header and footer stay in view. Swiping only starts once the body is scrolled to its edge.

No drag area

Add data-no-drag to an element inside the content to stop drags from starting on it, here a row of swatches that scrolls sideways.

Non draggable

Pass draggable={false} to Drawer.Content so drags on the content don't move the drawer. The grabber stays a drag handle; leave it out to turn off swipe to dismiss.

Indent background

Wrap the page in Drawer.Stack and Drawer.Indent to shrink it back behind the drawer, over a Drawer.IndentBackground. The indent follows the swipe, so the page grows again as you swipe the drawer away.

This box stands in for your page.

Stacked

Open a drawer from inside another and the one below shrinks and peeks out behind it, through the --nested-drawers variable. Closing the top drawer returns to the one behind it. Only the first drawer renders a backdrop.

Multiple triggers

Give each Drawer.Trigger a value to share one drawer. triggerValue on the drawer API says which one opened it, and onTriggerValueChange reports it.

Using the API

Create the drawer with useDrawer and pass it to Drawer.RootProvider to drive it from anywhere: setOpen() and setSnapPoint() change it, and open, snapPoint and triggerValue read it. useDrawer takes Zag's swipeDirection directly, and the recipe styles the drawer from it.