Drawer
An edge-anchored panel that slides in for details, navigation, and side tasks.
Show codeHide code
Installation
import { Drawer, DrawerTrigger, DrawerPanel } from "@makeplane/propel/components/drawer";Usage
import { Button } from "@makeplane/propel/components/button";
import {
Drawer,
DrawerBody,
DrawerClose,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerHeaderActions,
DrawerHeaderContent,
DrawerHeaderIcon,
DrawerHeaderStart,
DrawerPanel,
DrawerTitle,
DrawerTrigger,
} from "@makeplane/propel/components/drawer";
import { Icon } from "@makeplane/propel/components/icon";
import { IconButton } from "@makeplane/propel/components/icon-button";
import { Box, X } from "lucide-react";
/**
* Default use case: `sm` inline flush column absolutely positioned in a `relative` parent —
* overlays page content without pushing it.
*/
export default function BasicDemo() {
return (
<div className="relative h-[28rem] w-full overflow-hidden rounded-xl border border-subtle bg-layer-2">
<Drawer swipeDirection="right">
<div className="flex h-full items-center justify-center p-4">
<DrawerTrigger
render={<Button stretch="auto" variant="secondary" size="lg" label="Open details" />}
/>
</div>
<DrawerPanel variant="inline" side="end" size="sm">
<DrawerHeader>
<DrawerHeaderStart>
<DrawerHeaderIcon>
<Box />
</DrawerHeaderIcon>
<DrawerHeaderContent>
<DrawerTitle>Page details</DrawerTitle>
<DrawerDescription>Inline sm absolute column.</DrawerDescription>
</DrawerHeaderContent>
</DrawerHeaderStart>
<DrawerHeaderActions side="end">
<DrawerClose
render={
<IconButton
variant="ghost"
size="md"
aria-label="Close"
icon={<Icon icon={X} />}
/>
}
/>
</DrawerHeaderActions>
</DrawerHeader>
<DrawerBody>Sidebar content goes here.</DrawerBody>
<DrawerFooter>
<DrawerClose
render={<Button stretch="auto" variant="ghost" size="md" label="Cancel" />}
/>
<Button stretch="auto" variant="primary" size="md" label="Save" />
</DrawerFooter>
</DrawerPanel>
</Drawer>
</div>
);
}Examples
Use cases map to variant + size. Prefer backdrop off in demos (see Backdrop
for the opt-in). Prefer sm + inline (absolute flush column in a relative parent — does
not push siblings) unless the example is deliberately about a floating card in a parent shell
(Contained).
| Use case | variant |
size |
Placement |
|---|---|---|---|
| Default sidebar | inline |
sm |
Absolute in relative parent (no push) |
| Floating details | overlay |
md / lg |
document.body (inset card) |
| Under app chrome | contained |
md / lg |
Positioned parent container |
Overlay
Floating card over the app (document.body). No backdrop.
Show codeHide code
Contained
Floating card portaled into a positioned parent (e.g. main shell under a search topnav). Does not cover chrome outside that shell.
Panel portals into this parent shell only — below the topnav, no page scrim.
Show codeHide code
Side
side anchors the panel to the inline-start or inline-end edge. sm stays an absolute flush
column inside the relative parent.
Pair Drawer swipeDirection with side so swipe-to-dismiss matches the edge (Base UI defaults
to "down"):
side |
swipeDirection |
|---|---|
end |
right |
start |
left |
Show codeHide code
Size
sm 358px (inline absolute column), md 800px / lg 1024px (overlay cards). Header sockets:
title cluster on sm; icon toolbars on md/lg (aria-label the panel when there is no
DrawerTitle).
Show codeHide code
Backdrop
backdrop is opt-in (default off) and overlay-only — not available on inline or
contained. Pair <Drawer modal> with backdrop when the page should block behind an overlay
panel.
Show codeHide code
Nested
Stacked overlay drawers (no backdrop).
Show codeHide code
Detached triggers
createDrawerHandle() links triggers to a Drawer defined elsewhere in the tree; each trigger passes a payload the drawer renders through function-as-children.
Show codeHide code
Controlled
A controlled Drawer can intercept its own dismissal — here a draft raises a confirmation via eventDetails.cancel() before the panel closes.
Show codeHide code
Page shift
Wrap the page in a DrawerProvider with a DrawerIndentBackground before a DrawerIndent around the content and the Drawer. While any drawer in the provider is open, both indent parts carry data-active, so the page can scale inward and reveal the background behind it.
Open the drawer to indent this page.
Show codeHide code
API Reference
Drawer
The drawer Root that holds open state and gesture configuration. Uncontrolled by default; pass `defaultOpen` (uncontrolled) or `open` + `onOpenChange` (controlled). A behavior-only role that renders no element of its own (rules 1a, 2), so it lives in `components`; the styled parts live in `elements/drawer` and are grafted onto Base UI behavior here.
DrawerTrigger
The behavior that opens the drawer. A behavior-only role that carries no propel styling, so graft it onto a styled control via `render` — behavior part outer, styled part as the render target, so the control's look wins: ```tsx <DrawerTrigger render={<Button stretch="auto" variant="secondary" size="lg" label="Open details" />} />; ``` Base UI manages `aria-haspopup`/`aria-expanded` and focus restoration when the drawer closes. Maps 1:1 to `Drawer.Trigger`.
DrawerPanel
Convenience that composes drawer portal/viewport/popup boilerplate. Defaults to `inline` + `sm` (flush absolute column in a relative parent). `overlay` portals to `document.body`; `contained` requires a parent `container`. `backdrop` is overlay-only.
DrawerBackdrop
The dimmed overlay behind the drawer: Base UI's `Drawer.Backdrop` behavior grafted onto the shared `internal/Backdrop` surface (rule 4a). Fades in/out via Base UI's `data-starting-style`/`data-ending-style` transition hooks.
DrawerTitle
The accessible heading for the drawer: Base UI's `Drawer.Title` behavior (wired as the popup's `aria-labelledby` target) grafted onto the shared `internal/OverlayTitle` at `size="xl"` (body-md semibold per Figma; rule 4a).
DrawerDescription
Supporting text for the drawer: Base UI's `Drawer.Description` behavior (wired as the popup's `aria-describedby` target) grafted onto the shared `internal/OverlayDescription` at `size="md"` (body-xs per Figma; rule 4a).
DrawerHeader
The drawer's top region (the Figma header). Compose a start cluster (`DrawerHeaderStart` or `DrawerHeaderActions side="start"`) and an end cluster (`DrawerHeaderActions side="end"`) for the title/icon sockets.
DrawerHeaderStart
The header's inline-start title cluster (Figma narrow header). Holds an optional `DrawerHeaderIcon` / `IconButton` plus `DrawerHeaderContent` (title + description).
DrawerHeaderIcon
Decorative leading glyph beside the title inside `DrawerHeaderStart`. Sizes a bare svg/img child; interactive leading controls should be an `IconButton` instead. Bakes `aria-hidden`.
DrawerHeaderContent
The stacked title + description inside a `DrawerHeader`. Groups them at the header's inline-start so a corner close can sit opposite at the inline-end; a long title wraps instead of pushing the close off the row.
DrawerHeaderActions
Header icon-button toolbar. `side="start"` / `side="end"` pin the cluster to the header's inline edges (Figma top-left / top-right sockets). Pass `IconButton`s and/or `DrawerClose`.
DrawerBody
The drawer's main content region (the Figma body). Grows to fill the space between the header and footer and scrolls its own overflow.
DrawerFooter
The drawer's footer actions region (the Figma footer). Lays its actions at the inline-end.
DrawerClose
The behavior that closes the drawer when activated. A behavior-only role that carries no propel styling, so graft it onto a styled control via `render` — behavior part outer, styled part as the render target, so the control's look wins: ```tsx <DrawerClose render={ <IconButton variant="ghost" size="md" aria-label={closeLabel} icon={<Icon icon={X} />} /> } />; ``` Maps 1:1 to `Drawer.Close`. (The styled bare close control it replaces in this entry still lives at `elements/drawer` for assembling a drawer from the atoms.)
DrawerProvider
Optional context wrapper that coordinates indent effects across sibling drawers. Wrap `Drawer` (and any `DrawerIndent`/`DrawerIndentBackground`) in it when you need the page to shift as the drawer opens. A behavior-only provider role (rules 1a, 2), so it lives in `components`. Maps 1:1 to Base UI's `Drawer.Provider`.
DrawerIndent
Wraps page content that should scale/shift inward as the drawer opens (the indent effect). Place inside a `DrawerProvider`, around the `Drawer` root and your page. A behavior-only role (rules 1a, 2), so it lives in `components`. Maps 1:1 to Base UI's `Drawer.Indent`.
DrawerIndentBackground
Renders behind the indented page content so the area revealed by the indent effect has a backdrop color. Used alongside `DrawerIndent` inside a `DrawerProvider`. A behavior-only role (rules 1a, 2), so it lives in `components`. Maps 1:1 to Base UI's `Drawer.IndentBackground`.
DrawerSwipeArea
An off-screen edge hit area that lets users swipe the closed drawer open from the screen edge. Optional; render it as a sibling of the trigger. A behavior-only role (rules 1a, 2), so it lives in `components`. Maps 1:1 to Base UI's `Drawer.SwipeArea`.