Drawer

A modal native <dialog> pinned to the start or end edge, full height. Drawer.Root takes the same props as Dialog.Root plus side, and the inside is built from Dialog's parts: Dialog.Header, Dialog.Title, Dialog.Description, Dialog.Body, Dialog.Footer and Dialog.Close.

side is end by default. Start and end follow text direction, so in right-to-left text end is the left edge.

Filters

The panel fills the height of the viewport and scrolls on its own.

Filters

The panel fills the height of the viewport and scrolls on its own.
<Drawer.Root open={open} onOpenChange={setOpen}>
  <Dialog.Header>
    <Dialog.Title>Filters</Dialog.Title>
    <Dialog.Close>Close</Dialog.Close>
  </Dialog.Header>
  <Dialog.Body>…</Dialog.Body>
</Drawer.Root>

When to use

When: A modal side panel for a task that needs room, such as filters, settings or details beside a list. Name it with Dialog.Title or aria-label.

When not: A short centered task or confirm → Dialog. A mobile picker from the bottom → BottomSheet. A panel that leaves the page usable → product layout, not a modal.

Props

Drawer.Root props
NameTypeRequiredDefaultDescription
openbooleanno—Controlled open state. Leave it out for an uncontrolled drawer.
defaultOpenbooleannofalseShows the drawer on mount when uncontrolled. There is no trigger part, so once closed it opens again only on remount.
onOpenChange(open: boolean, reason: DialogCloseReason) => voidno—Dismiss requests, with the same reasons as Dialog.Root.
side'start' | 'end'no'end'Inline edge it is pinned to. Follows text direction.
dismissOnEscapebooleannotrueEscape calls onOpenChange(false, "escape").
dismissOnBackdropbooleannotrueScrim click calls onOpenChange(false, "backdrop").
aria-labelstringno—Name when Dialog.Title is omitted.