Drawer
Open an edge panel with swipe dismissal.
Installation
pnpm dlx shadcn@4.18.0 add @siteplane/drawerComplete the one-time setup first. Registry JSON lists source files and dependencies.
For this page’s examples, also install:
pnpm dlx shadcn@4.18.0 add @siteplane/avatar @siteplane/avatar-group @siteplane/badge @siteplane/button @siteplane/card @siteplane/checkbox-group @siteplane/data-list @siteplane/fieldset @siteplane/file-type-icon @siteplane/label @siteplane/progress @siteplane/radio-group @siteplane/resource-list @siteplane/separator @siteplane/toggle-groupUsage
import { Button } from "@/siteplane/components/button";
import {
Drawer,
DrawerTrigger,
DrawerPopup,
DrawerHeader,
DrawerTitle,
DrawerDescription,
DrawerPanel,
DrawerFooter,
DrawerClose,
} from "@/siteplane/components/drawer";
<Drawer>
<DrawerTrigger render={<Button variant="outline" />}>Open</DrawerTrigger>
<DrawerPopup showBar>
<DrawerHeader>
<DrawerTitle>Project details</DrawerTitle>
<DrawerDescription>Owner, status and due date.</DrawerDescription>
</DrawerHeader>
<DrawerPanel>Content</DrawerPanel>
<DrawerFooter>
<DrawerClose render={<Button variant="ghost" />}>Close</DrawerClose>
</DrawerFooter>
</DrawerPopup>
</Drawer>;Composition
Drawer
├── DrawerTrigger
└── DrawerPopup
├── DrawerHeader
│ ├── DrawerTitle
│ └── DrawerDescription
├── DrawerPanel
└── DrawerFooter
└── DrawerCloseMobile menu
Open navigation from the left edge on small screens. The header holds the app’s mark and name, the menu groups the destinations and marks the current page with aria-current="page", and the footer pins the account row. size="xl" gives the rows touch size: 48 px high, 16 px text and 20 px icons. Keep the items as links and close the drawer when one is chosen.
Action menu
Compose the DrawerMenu parts into an action sheet, here for a file in a mobile app. Menu items don’t close the drawer on their own, so wrap them in DrawerClose; DrawerMenuTrigger opens a nested drawer. The parts keep real checkbox, switch and radio semantics; DrawerMenu is a navigation region, not an ARIA menu with roving focus. A touch screen turns the rows into 48 px rows; pass size="xl" for that size at every pointer.
Position
position on Drawer sets the edge and the matching swipe direction. The popup, bar and swipe area inherit it, so set it on the root. Each edge suits its own content: notifications drop from the top, details open on the right, short confirmations rise from the bottom and switchers slide in from the left. The workspace switcher is a DrawerMenuRadioGroup whose rows lead with the workspace's avatar and end with the check (indicatorPosition="end"), like the identity rows of Menu.
Width
On wide screens a bottom or top drawer keeps a readable width (max-w-lg, 512 px) and centers itself. Set width="full" on DrawerPopup to let it span the whole edge instead, for a tray with a row of actions. Left and right drawers keep their own width, and a phone shows both widths alike because the screen is narrower than 512 px. The straight variant stays attached along the whole edge, so it is full width by default; width="readable" narrows it again.
Variants
inset floats the drawer away from the viewport edges on larger screens. straight removes the rounded corners and the elevation and keeps the panel attached to its edge, at full width for the bottom and the top (see Width).
Scrollable content
DrawerPanel scrolls when the content is taller than the drawer; the header and footer stay in place.
Snap points
Pass snapPoints to rest a bottom drawer at a compact height before it expands to full height. Numbers between 0 and 1 are fractions of the viewport height; strings accept px and rem. Control the active point with snapPoint and onSnapPointChange.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
Drawer. | bottom | top | left | right | bottom | Shared edge and inferred swipe direction. |
Drawer. | down | up | left | right | derived from position | Override swipe direction. |
Drawer | bottom | top | left | right | root position | Local edge override. |
Drawer | default | straight | inset | default | Surface and viewport layout. |
Drawer | readable | full | readable; full for straight | Width of a bottom or top panel on a wide screen. readable caps it at 512 px (max-w-lg) and centers it; full spans the whole edge. Left and right panels keep their own width. |
Drawer | default | none | default; none for straight | default draws the floating shadow and its edge; none removes both. A straight drawer always has none and draws a hairline along its inner edge instead. |
Drawer | boolean | false | Optional automatic close control or drag bar. |
Drawer | DrawerPrimitive.Close.Props | unset | Overrides the automatic close control, including aria-label (default: Close). |
Drawer | DrawerPrimitive.Portal.Props | unset | Portal configuration. |
Drawer | bottom | top | left | right | unset | Low-level viewport; Popup supplies resolved position. |
Drawer | boolean | false | Allow text selection instead of header dragging. |
Drawer | boolean | true | Allow text selection. |
Drawer | boolean | true | Scroll fade and scroll-area rendering. |
Drawer | default | destructive | default | Action tone. A destructive item colors its label and its icon red. |
Drawer | boolean | false | Prevents action. |
Drawer | sm | md | lg | xl | provider / lg | Row size. xl is the touch size: 48 px rows with 16 px text and 20 px icons. The other sizes keep the compact menu rows, which a touch screen also turns into 48 px rows. |
Drawer | default | switch | default | Checkbox or switch presentation. |
Drawer | string | required | Selection value. |
Drawer | start | end | start | Where the check shows: in the leading slot, or at the end of an identity row that leads with a logo or an avatar. |
DrawerPopup includes Portal, Backdrop and Viewport automatically. DrawerContent is an alias of DrawerPopup, as in the other overlays. DrawerPortal is a direct foundation export. DrawerTrigger, Close, SwipeArea, Title and Description wrap Base UI Drawer. DrawerBackdrop/Viewport are available for low-level composition. DrawerBar is the visual drag handle. DrawerCreateHandle creates detached-trigger handles; DrawerPrimitive exposes the namespace. DrawerPosition is not exported as a named type.
Header, Footer, Panel, Bar, MenuItem, MenuSeparator, MenuGroup and MenuGroupLabel accept useRender div/button props according to their element; DrawerMenu renders nav. DrawerMenuTrigger accepts Trigger props except render and supplies its own Button/chevron. DrawerMenuCheckboxItem accepts Checkbox props and becomes a Switch when variant is switch. DrawerMenuRadioGroup accepts RadioGroup props, and DrawerMenuRadioItem accepts Radio props with a string value. The choice parts style themselves as menu rows. Plain menu actions do not close the drawer automatically. All styled className props are strings. Foundation snap points, nesting, focus, modal state, dismissal and events remain available on their corresponding root/parts.
open/defaultOpen choose controlled/initial state (closed by default); onOpenChange(open, eventDetails) requests a transition and onOpenChangeComplete(open) reports motion completion. Initial/final focus and dismissal behavior belong to the underlying foundation.
DrawerMenuSeparator, DrawerMenuGroup, and DrawerMenuGroupLabel accept useRender div props. They supply the menu divider, group layout, and label styling respectively, without selection state or roving focus of their own.
Usage notes
Provide a title, clear close action and meaningful focus target. Escape and focus restoration follow the foundation. Application loading, errors and async confirmation must be represented explicitly in the content. Do not treat swipe dismissal as the only way to close.