Components
Drawer
View in FigmaA side-sheet drawer — built on the same Base UI Dialog primitive as Dialog, but the popup is a full-height panel that slides in from the edge. Drawer is the state root; trigger and close render your element via Base UI's render prop, so a Button keeps its full API.
Install
npx shadcn@latest add @alix/drawerPreview
Usage
<Drawer>
<DrawerTrigger render={<Button>Filters</Button>} />
<DrawerContent side="right">
<DrawerHeader>
<DrawerTitle>Filters</DrawerTitle>
<DrawerDescription>Narrow the results.</DrawerDescription>
</DrawerHeader>
<DrawerBody>…form fields…</DrawerBody>
<DrawerFooter>
<DrawerClose render={<Button variant="outline">Cancel</Button>} />
<Button onClick={() => apply()}>Apply</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>Examples
01
Left-side navigation
Use side="left" when the drawer behaves like a temporary navigation or workspace switcher.
<Drawer>
<DrawerTrigger render={<Button variant="outline">Open workspace</Button>} />
<DrawerContent side="left">
<DrawerHeader>
<DrawerTitle>Workspaces</DrawerTitle>
<DrawerDescription>Switch between active engagements.</DrawerDescription>
</DrawerHeader>
<DrawerBody className="flex flex-col gap-2">
<a className="border border-border p-3 text-sm" href="#">Project Atlas</a>
<a className="border border-border p-3 text-sm" href="#">Northstar Retail</a>
<a className="border border-border p-3 text-sm" href="#">Cobalt Health</a>
</DrawerBody>
</DrawerContent>
</Drawer>02
Filter panel
Drawer gives filters room for fields and checkbox groups while keeping apply actions pinned in the footer.
<Drawer>
<DrawerTrigger render={<Button>Filter engagements</Button>} />
<DrawerContent side="right">
<DrawerHeader>
<DrawerTitle>Filter engagements</DrawerTitle>
<DrawerDescription>Refine the active portfolio view.</DrawerDescription>
</DrawerHeader>
<DrawerBody className="flex flex-col gap-5">
<Field label="Capability">
<Select
placeholder="Any capability"
items={[
{ value: "turnaround", label: "Turnaround" },
{ value: "transactions", label: "Transactions" },
]}
/>
</Field>
<div className="flex flex-col gap-3">
<span className="text-sm font-medium text-foreground">Status</span>
<label className="flex items-center gap-2 text-sm">
<Checkbox defaultChecked /> On track
</label>
<label className="flex items-center gap-2 text-sm">
<Checkbox /> At risk
</label>
</div>
</DrawerBody>
<DrawerFooter>
<DrawerClose render={<Button variant="outline">Reset</Button>} />
<DrawerClose render={<Button>Apply filters</Button>} />
</DrawerFooter>
</DrawerContent>
</Drawer>03
Engagement detail
A detail drawer can scan like a side panel with badges, facts, and secondary actions.
<Drawer>
<DrawerTrigger render={<Button variant="outline">View details</Button>} />
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Project Atlas</DrawerTitle>
<DrawerDescription>Turnaround and restructuring</DrawerDescription>
</DrawerHeader>
<DrawerBody className="flex flex-col gap-4">
<div className="flex flex-wrap gap-2">
<Badge variant="success" dot>On track</Badge>
<Badge variant="primary">Phase 2</Badge>
</div>
<dl className="grid grid-cols-2 gap-4 text-sm">
<div>
<dt className="text-muted-foreground">Lead</dt>
<dd className="font-medium text-foreground">Amelia Ward</dd>
</div>
<div>
<dt className="text-muted-foreground">Next review</dt>
<dd className="font-medium text-foreground">Friday</dd>
</div>
</dl>
</DrawerBody>
<DrawerFooter>
<DrawerClose render={<Button variant="outline">Close</Button>} />
<Button>Open workspace</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>When to use it
Use it for
- Filters, navigation, and detail panels that need more room than a popover while preserving page context.
- Longer side content with a scrollable body and persistent footer actions.
- Right-side task panels and left-side workspace or navigation panels.
Reach for something else
- Focused blocking confirmation or create flows — use Dialog instead.
- Small anchored explanations or local edits — use Popover instead.
- Command lists with only actions or links — use Menu instead.
- Non-blocking save confirmations — use Toast instead.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| Drawer | open?, defaultOpen?, onOpenChange?, modal? | — | The state root (shared Base UI Dialog.Root). |
| DrawerContent | side?: "right" | "left" | "right" | The portalled scrim + full-height side panel; side picks the edge it anchors to and slides in from. Includes an automatic close button. |
| DrawerTrigger / DrawerClose | render: ReactElement | — | Open/close via the render prop, keeping the passed element's full API. |
| DrawerHeader / DrawerTitle / DrawerDescription / DrawerBody / DrawerFooter | children | — | Structural slots: bordered header, scrollable body region, and a bordered, right-aligned footer action row. |