A `Card` docked to one edge of the viewport as a slide-in panel, built on [Radix `Dialog`](https://www.radix-ui.com/primitives/docs/components/dialog) for focus trapping, Escape-to-close, and outside-click-to-close. It has no opinion on what goes inside the panel — an optional `title` renders a header with a close button, otherwise just the `children` are shown.

pnpm add @behivetech/atoms.drawer

You are viewing Drawer v0.4.8, snapshotted 2026-11-09. The latest is v0.4.10. Go to the latest →

A Card docked to one edge of the viewport as a slide-in panel, built on Radix Dialog for focus trapping, Escape-to-close, and outside-click-to-close. It has no opinion on what goes inside the panel — an optional title renders a header with a close button, otherwise just the children are shown.

placement controls which edge it docks to; backdrop controls whether it blocks the rest of the page or floats alongside content the user can keep interacting with, e.g. an always-visible properties panel. For a centered dialog that always blocks the page, use @behivetech/atoms.modal instead.

Usage

1import { Drawer } from '@behivetech/atoms.drawer';
2
3// A blocking panel docked to the right edge — closes on backdrop click
4<Drawer onClose={() => setOpen(false)} title="Add Block" placement="right">
5 <div>Panel content</div>
6</Drawer>
7
8// A non-blocking panel docked to the right edge — the rest of the page stays
9// interactive, and clicking outside the panel does not close it
10<Drawer onClose={() => setSelected(null)} title="Block" placement="right" backdrop={false}>
11 <div>Properties form</div>
12</Drawer>

Properties

Drawer props

PropTypeDefaultDescription
children*ReactNode—Panel content
onClose*() => void—Called when the drawer is dismissed (backdrop click, Escape, or the close button)
placement*"top" | "right" | "bottom" | "left"—Which edge the panel slides in from
backdropbooleantrueWhether a dimmed backdrop covers the rest of the page, blocks interaction with it, and closes the drawer when clicked — a real modal. Defaults to true. Set false for a non-blocking panel that floats alongside content the user can keep interacting with, e.g. an always-visible properties panel that updates as a different item is selected behind it.
classNamestring—Additional class names to merge with the component root element
headingLevel1 | 2 | 3 | 4 | 5 | 6—Which heading tag wraps `title` — same values as `Card`'s `headingLevel` prop
iconReactNode—Optional icon rendered before the title in the header; ignored if `title` is omitted
padding"none" | "sm" | "md" | "lg"—Internal padding of the panel body — same values as `Card`'s `padding` prop
titlestring—Optional header title; omit to render no header and no close button

Also accepts the native attributes of its root element (className, aria-*, event handlers, …).