Catalog npm
PACKAGE EXPLORERView in registry

@01-collective/drawer-svelte

npm

Svelte 5 drawer/bottom-sheet component with native drag gestures, inspired by Vaul

bits-uibottom-sheetdialogdrawermodalsheetsveltesvelte5vaulvaul-svelte
Versions collected1
Direct dependencies15From release 0.1.0
Last observed20 Oct, 21:54 UTC

README

Current package documentation

@01-collective/drawer-svelte

A Svelte 5 drawer component — inspired by Vaul. A drawer/bottom-sheet component with native-feeling drag gestures. Built on top of Bits UI Dialog.

Installation

npm install @01-collective/drawer-svelte

Quick Start

Wrap your app content in a data-svelte-drawer-drawer-wrapper element (typically in your root layout or app.html):

<body>
  <div data-svelte-drawer-drawer-wrapper="">
    %sveltekit.body%
  </div>
</body>

Then use the drawer:

<script>
  import { Drawer } from '@01-collective/drawer-svelte';
</script>

<Drawer.Root>
  <Drawer.Trigger>Open</Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Overlay class="overlay" />
    <Drawer.Content class="content">
      <Drawer.Handle />
      <Drawer.Title>Title</Drawer.Title>
      <Drawer.Description>Description</Drawer.Description>
      <Drawer.Close>Close</Drawer.Close>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer.Root>

Features

  • Drag to dismiss — flick or drag past threshold to close
  • Snap points — multiple stop positions (fraction or px)
  • All directions — bottom, top, left, right
  • Nested drawers — drawers within drawers
  • Background scaling — iOS-style sheet effect
  • Keyboard handling — repositions inputs when virtual keyboard opens
  • Mobile scroll lock — prevents body scroll on iOS Safari
  • Modal & non-modal — with proper focus trapping
  • Accessible — built on Bits UI Dialog (WAI-ARIA compliant)
  • Headless — unstyled, bring your own CSS

Components

ComponentDescription
Drawer.RootState manager, wraps everything
Drawer.TriggerButton that opens the drawer
Drawer.PortalRenders content in a portal
Drawer.OverlayBackdrop behind the drawer
Drawer.ContentThe drawer panel (handles drag events)
Drawer.HandleDrag handle with snap point cycling
Drawer.CloseButton that closes the drawer
Drawer.TitleAccessible title
Drawer.DescriptionAccessible description
Drawer.NestedRootRoot for nested drawers

Props

Drawer.Root

PropTypeDefaultDescription
openbooleanfalseControlled 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
fadeFromIndexnumberlast snap pointOverlay fades from this snap point index
activeSnapPointnumber | string | null—Controlled active snap point
setActiveSnapPoint(point) => void—Callback when snap point changes
closeThresholdnumber0.25Fraction of height to trigger close
dismissiblebooleantrueWhether the drawer can be closed
modalbooleantrueModal mode with focus trap
handleOnlybooleanfalseOnly allow dragging via Handle
shouldScaleBackgroundbooleanfalseScale background on open
nestedbooleanfalseIs this a nested drawer
noBodyStylesbooleanfalseDon't apply body styles
fixedbooleanfalseOnly change height on keyboard open
autoFocusbooleanfalseAuto-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

Examples

Snap Points

<Drawer.Root snapPoints={[0.25, 0.5, 1]} fadeFromIndex={1}>
  <Drawer.Trigger>Open</Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Overlay />
    <Drawer.Content>
      <Drawer.Handle />
      <p>Drag to snap points at 25%, 50%, and 100%</p>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer.Root>

Right Drawer

<Drawer.Root direction="right">
  <Drawer.Trigger>Open</Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Overlay />
    <Drawer.Content>
      <p>Slides in from the right</p>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer.Root>

Nested Drawers

<Drawer.Root>
  <Drawer.Trigger>Open Outer</Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Overlay />
    <Drawer.Content>
      <Drawer.NestedRoot>
        <Drawer.Trigger>Open Inner</Drawer.Trigger>
        <Drawer.Portal>
          <Drawer.Overlay />
          <Drawer.Content>
            <p>Nested drawer content</p>
          </Drawer.Content>
        </Drawer.Portal>
      </Drawer.NestedRoot>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer.Root>

Background Scaling

<Drawer.Root shouldScaleBackground>
  <!-- ... -->
</Drawer.Root>

Controlled State

<script>
  let open = $state(false);
</script>

<button onclick={() => open = true}>Open programmatically</button>

<Drawer.Root bind:open>
  <Drawer.Portal>
    <Drawer.Overlay />
    <Drawer.Content>
      <p>Controlled drawer</p>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer.Root>

Prevent Closing

<Drawer.Root dismissible={false}>
  <!-- User cannot drag-to-close or click overlay to close -->
</Drawer.Root>

Non-modal

<Drawer.Root modal={false}>
  <!-- No overlay, no focus trap, interact with page behind -->
</Drawer.Root>

Styling

The component is headless. Style using classes, inline styles, or 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: 10px 10px 0 0;
}

Data Attributes

AttributeValuesElement
data-svelte-drawer-drawer—Content
data-svelte-drawer-drawer-directiontop|bottom|left|rightContent
data-svelte-drawer-overlay—Overlay
data-svelte-drawer-handle—Handle
data-svelte-drawer-snap-pointstrue|falseContent, Overlay
data-svelte-drawer-drawer-visibletrue|falseHandle
data-svelte-drawer-no-drag—Any element (prevents drag)
data-stateopen|closedContent, Overlay

Credits

  • Svelte Drawer by Emil Kowalski — original React implementation
  • Bits UI — accessible Svelte 5 primitives

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.0Registry latest14 Mar 202615

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:54 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:0141bb67511dc39528e3d0bfc53213882b45a800c0618094d3ea35fb2c07a7c6