Drawer
Installation
Section titled “Installation”npx bambiui add drawerImport the token file once from your global stylesheet:
@import "./styles/bambi.css";Then import the component:
import { DrawerRoot, DrawerTrigger, DrawerPortal, DrawerOverlay, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerBody, DrawerFooter, DrawerClose,} from './components/ui/drawer';<script> import Drawer from './components/ui/Drawer.svelte';</script><script setup>import Drawer from './components/ui/Drawer.vue';</script>---import Drawer from './components/ui/Drawer.astro';---API Styles
Section titled “API Styles”Use props-driven root props for common drawers. Use the compound API for advanced layouts, custom structure, or full control. Both styles preserve the same dialog, overlay, close, header, body, and footer structure.
Props-driven Usage
Section titled “Props-driven Usage”const [open, setOpen] = useState(false);
<DrawerRootopen={open}onOpenChange={setOpen}trigger={<Button>Open Drawer</Button>}title="Edit profile"description="Make changes to your profile here."footer={<Button onClick={() => setOpen(false)}>Save</Button>}side="right"size="md">Your content goes here.</DrawerRoot>{#snippet trigger()}<button type="button">Open Drawer</button>{/snippet}
{#snippet footer()}<button type="button">Save</button>{/snippet}
<Drawer{trigger}{footer}title="Edit profile"description="Make changes to your profile here."side="right"size="md">Your content goes here.</Drawer><Drawertitle="Edit profile"description="Make changes to your profile here."side="right"size="md"><template #trigger> <button type="button">Open Drawer</button></template>Your content goes here.<template #footer> <button type="button">Save</button></template></Drawer><button type="button" data-drawer-open="profile-drawer">Open Drawer</button>
<Drawerid="profile-drawer"title="Edit profile"description="Make changes to your profile here."side="right"size="md">Your content goes here.<button slot="footer" type="button" data-drawer-close="profile-drawer">Save</button></Drawer>Compound Usage
Section titled “Compound Usage”const [open, setOpen] = useState(false);
<DrawerRoot open={open} onOpenChange={setOpen} side="right" size="md"><DrawerTrigger onClick={() => setOpen(true)}>Open Drawer</DrawerTrigger><DrawerPortal> <DrawerOverlay /> <DrawerContent> <DrawerClose /> <DrawerHeader> <DrawerTitle>Edit profile</DrawerTitle> <DrawerDescription>Make changes to your profile here.</DrawerDescription> </DrawerHeader> <DrawerBody> <p>Your content goes here.</p> </DrawerBody> <DrawerFooter> <Button onClick={() => setOpen(false)}>Save</Button> </DrawerFooter> </DrawerContent></DrawerPortal></DrawerRoot><script>let open = $state(false);</script>
<button type="button" onclick={() => (open = true)}>Open Drawer</button>
<Drawer bind:open={open} side="right" size="md"><div class="bambi-drawer-header"> <h2 class="bambi-drawer-title">Edit profile</h2> <p class="bambi-drawer-description">Make changes to your profile here.</p></div><div class="bambi-drawer-body"> <p>Your content goes here.</p></div><div class="bambi-drawer-footer"> <button type="button" onclick={() => (open = false)}>Save</button></div></Drawer><script setup>const open = ref(false);</script>
<template><button type="button" @click="open = true">Open Drawer</button>
<Drawer :open="open" @open-change="(v) => (open = v)" side="right" size="md"> <div class="bambi-drawer-header"> <h2 class="bambi-drawer-title">Edit profile</h2> <p class="bambi-drawer-description">Make changes here.</p> </div> <div class="bambi-drawer-body"> <p>Your content goes here.</p> </div> <div class="bambi-drawer-footer"> <button type="button" @click="open = false">Save</button> </div></Drawer></template><button type="button" data-drawer-open="my-drawer">Open Drawer</button>
<Drawer id="my-drawer" side="right" size="md"><div class="bambi-drawer-header"> <h2 class="bambi-drawer-title">Edit profile</h2> <p class="bambi-drawer-description">Make changes here.</p></div><div class="bambi-drawer-body"> <p>Your content goes here.</p></div><div class="bambi-drawer-footer"> <button type="button" data-drawer-close="my-drawer">Save</button></div></Drawer><DrawerRoot side="right">...</DrawerRoot><DrawerRoot side="left">...</DrawerRoot><DrawerRoot side="top">...</DrawerRoot><DrawerRoot side="bottom">...</DrawerRoot><Drawer side="right">...</Drawer><Drawer side="left">...</Drawer><Drawer side="top">...</Drawer><Drawer side="bottom">...</Drawer><Drawer side="right">...</Drawer><Drawer side="left">...</Drawer><Drawer side="top">...</Drawer><Drawer side="bottom">...</Drawer><Drawer side="right">...</Drawer><Drawer side="bottom">...</Drawer>| Value | Width / Height |
|---|---|
sm | 20rem |
md | 28rem (default) |
lg | 36rem |
xl | 48rem |
full | 100vw / 100dvh |
CSS Classes
Section titled “CSS Classes”| Class | Element |
|---|---|
bambi-drawer-overlay | Background dimmer |
bambi-drawer-content | The drawer panel |
bambi-drawer-header | Header section |
bambi-drawer-title | Title <h2> |
bambi-drawer-description | Description text |
bambi-drawer-body | Scrollable content area |
bambi-drawer-footer | Footer action area |
bambi-drawer-close | Close × button |
API Reference
Section titled “API Reference”DrawerRoot / <Drawer>
Section titled “DrawerRoot / <Drawer>”| Prop | Type | Default | Description |
|---|---|---|---|
side | 'top' | 'right' | 'bottom' | 'left' | 'right' | Which edge the drawer slides from |
size | 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'md' | Panel width or height |
defaultOpen | boolean | false | Initial open state (uncontrolled) |
open | boolean | — | Controlled open state |
closeOnOverlayClick | boolean | true | Close when clicking the overlay |
onOpenChange | (open: boolean) => void | — | Called when open state changes |
trigger | framework node/snippet/slot | — | Convenience trigger content where supported |
title | framework text/node prop | — | Convenience dialog title |
description | framework text/node prop | — | Convenience dialog description |
footer | framework node/snippet/slot | — | Convenience footer content |
Astro data attributes (triggers)
Section titled “Astro data attributes (triggers)”In Astro, open/close is wired via data attributes on any element in the page:
| Attribute | Value | Effect |
|---|---|---|
data-drawer-open | drawer id | Opens the drawer on click |
data-drawer-close | drawer id | Closes the drawer on click |
Accessibility
Section titled “Accessibility”- The drawer content uses
role="dialog"andaria-modal="true". DrawerTitleis automatically linked to the dialog viaaria-labelledby.DrawerDescriptionis linked viaaria-describedby.- Focus is trapped inside the drawer while open (Tab / Shift+Tab cycle within the panel).
- Pressing Escape closes the drawer.
- Focus is restored to the trigger element when the drawer closes.
- While open, background content has the
inertattribute set, making it unreachable by keyboard and screen readers. - All interactive elements must be keyboard-accessible; mouse-only interactions are not required.