Drawer

A panel that slides in from the edge of the screen, and can be swiped away.

import { Button } from "@hel/ui/button"
import { Checkbox, CheckboxLabel } from "@hel/ui/checkbox"
import {

When to use it

Use a drawer for work that is bigger than a popover but should keep the person in the context of the page: editing a record from a list, a filter panel, a navigation menu on a phone. It slides in from an edge, and the page behind it stays in place.

On a small screen a drawer from the bottom feels natural, because people can swipe it away with a thumb. For a short question or a small form in the middle of the screen, use a Dialog.

Import

import {
  Drawer,
  DrawerTrigger,
  DrawerContent,
  DrawerHeader,
  DrawerTitle,
  DrawerDescription,
  DrawerBody,
  DrawerFooter,
  DrawerClose,
} from "@hel/ui/drawer"

Anatomy

Drawer holds the open state, and DrawerTrigger opens it. DrawerContent is the panel, together with the dimmed backdrop. It is split into three parts, so that long content scrolls in the right place:

  • DrawerHeader is fixed at the top. It groups the DrawerTitle and the DrawerDescription, and has a close button at the end of the row. Set showClose={false} to leave the button out.
  • DrawerBody is the only part that scrolls.
  • DrawerFooter is pinned to the bottom, for the buttons.

DrawerClose closes the drawer when its element is pressed. Pass the button with render, so the two are one element.

<Drawer>
  <DrawerTrigger render={<Button variant="outline">Edit customer</Button>} />
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Edit customer</DrawerTitle>
    </DrawerHeader>
    <DrawerBody>...</DrawerBody>
    <DrawerFooter>
      <DrawerClose render={<Button variant="outline">Cancel</Button>} />
    </DrawerFooter>
  </DrawerContent>
</Drawer>

Escape, a click on the backdrop, and a swipe toward the edge it came from all close the drawer.

Examples

Sides

side on Drawer is the edge the panel comes from: right, the default, left or bottom. The direction of the swipe that closes it follows automatically, so the gesture and the edge always match. A bottom drawer shows a small grab handle at the top, which tells people it can be swiped. Use showHandle on the content to turn it on or off for any side.

import { Button } from "@hel/ui/button"
import {
  Drawer,

Looks

The panel floats a little away from the edge of the screen, with rounded corners. margin on DrawerContent sets that gap, using the spacing scale, and it defaults to sm. disableAnimation removes the slide and fade.

Nested drawers

A drawer inside the body of another drawer is treated as nested. The first one steps back slightly while the second is open, so the stack is easy to read.

Props

Drawer

PropTypeDefault
side"right" | "left" | "bottom""right"
open / defaultOpenbooleanfalse
onOpenChange(open: boolean) => voidnone
modalbooleantrue

It also takes every prop of the Base UI drawer.

DrawerContent

PropTypeDefault
margina spacing step"sm"
showHandlebooleantrue for bottom, otherwise false
containeran elementThe page
disableAnimationbooleanfalse

DrawerHeader

PropTypeDefault
showClosebooleantrue