Documentation
Installation
npm install @01-collective/drawer bits-uiSetup
Wrap your app content in a data-svelte-drawer-drawer-wrapper element. In SvelteKit, add it to app.html:
<body>
<div data-svelte-drawer-drawer-wrapper="">
%sveltekit.body%
</div>
</body> This wrapper is required for the background scaling effect. If you don't use shouldScaleBackground, it's still recommended for consistency.
Basic Usage
<script>
import { Drawer } from '@01-collective/drawer';
</script>
<Drawer.Root>
<Drawer.Trigger>Open</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Handle />
<Drawer.Title>Title</Drawer.Title>
<Drawer.Description>Description</Drawer.Description>
<Drawer.Close>Close</Drawer.Close>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>Components
| Component | Description |
|---|---|
Drawer.Root | State manager. Wraps everything. |
Drawer.Trigger | Button that opens the drawer. |
Drawer.Portal | Renders content in a portal. |
Drawer.Overlay | Backdrop behind the drawer. |
Drawer.Content | The drawer panel. Handles drag events. |
Drawer.Handle | Drag handle with snap point cycling on tap. |
Drawer.Close | Button that closes the drawer. |
Drawer.Title | Accessible title (required for a11y). |
Drawer.Description | Accessible description. |
Drawer.NestedRoot | Root for nested drawers. |
Props — Drawer.Root
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Controlled open state (bindable) |
onOpenChange | (open: boolean) => void | — | Called when open state changes |
direction | 'top' | 'bottom' | 'left' | 'right' | 'bottom' | Drawer direction |
snapPoints | (number | string)[] | — | Snap points as fractions (0–1) or px strings |
fadeFromIndex | number | last | Overlay fades from this snap point index |
closeThreshold | number | 0.25 | Fraction of height to trigger close |
dismissible | boolean | true | Whether the drawer can be closed by user |
modal | boolean | true | Modal mode with focus trap & overlay |
handleOnly | boolean | false | Only allow dragging via Handle |
shouldScaleBackground | boolean | false | Scale background wrapper on open |
nested | boolean | false | Is this a nested drawer |
noBodyStyles | boolean | false | Don't apply body styles |
fixed | boolean | false | Only change height when keyboard opens |
autoFocus | boolean | false | Auto-focus content on open |
onDrag | (event, progress) => void | — | Called during drag |
onRelease | (event, open) => void | — | Called on drag release |
onClose | () => void | — | Called when drawer closes |
onAnimationEnd | (open: boolean) => void | — | Called after open/close animation |
Data Attributes
| Attribute | Element | Description |
|---|---|---|
data-svelte-drawer-drawer | Content | Marks the drawer element |
data-svelte-drawer-drawer-direction | Content | top | bottom | left | right |
data-svelte-drawer-overlay | Overlay | Marks the overlay |
data-svelte-drawer-handle | Handle | Marks the handle |
data-svelte-drawer-snap-points | Content, Overlay | true when snap points active |
data-svelte-drawer-no-drag | Any | Prevents drag on this element |
data-state | Content, Overlay | open | closed |
Styling
The component is headless — no styles are applied to visible elements. Use classes, inline styles, or target data attributes:
[data-svelte-drawer-overlay] {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
}
[data-svelte-drawer-drawer] {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
border-radius: 12px 12px 0 0;
} The library ships CSS for animations and transitions on [data-svelte-drawer-drawer] and [data-svelte-drawer-overlay]. These are bundled automatically when you import any component.