svelte-base-drawer

A Svelte 5 port of Base UI's Drawer (v1.9.0), built on bits-ui Dialog. Swipe to dismiss with momentum, snap points, nested drawers, swipe to open, virtual keyboard support. Unstyled — you own the CSS. MIT licensed, not affiliated with MUI.

Install

npm install svelte-base-drawer

bits-ui is a peer dependency: the drawer wraps its Dialog for focus management, portals and accessibility. If your project doesn't already use it, install it as well: npm install bits-ui.

Usage

The anatomy mirrors Base UI. Drawer.Viewport is required — it hosts all swipe and touch-scroll handling. Components ship unstyled: import svelte-base-drawer/drawer.css as a starter stylesheet, or style the data attributes yourself (each demo below has its own CSS).

<script>
  import * as Drawer from 'svelte-base-drawer';
</script>

<Drawer.Root>
  <Drawer.Trigger>Open</Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Backdrop />
    <Drawer.Viewport>          <!-- required: hosts all swipe handling -->
      <Drawer.Popup>           <!-- the panel -->
        <Drawer.Handle />
        <Drawer.Title>Title</Drawer.Title>
        <Drawer.Description>Description</Drawer.Description>
        <Drawer.Content>       <!-- the scrollable region -->
          Your content here
        </Drawer.Content>
        <Drawer.Close>Close</Drawer.Close>
      </Drawer.Popup>
    </Drawer.Viewport>
  </Drawer.Portal>
</Drawer.Root>

Basic drawer

Swipe down to dismiss, or tap the backdrop. Catch it mid-animation.

Snap points

Drag the sheet to snap between a compact peek and a near full-height view.

Nested drawers

Nested drawers stack with a scale effect while staying independently focus managed.

Virtual keyboard aware

On mobile, focused fields stay visible above the software keyboard.

Rich text editor

A Tiptap editor in a full-height side drawer: the caret lands where you tap, and deleted images keep the content reachable above the keyboard.

Indent effect

The app surface scales down behind the drawer, iOS style.

Mobile navigation

A tall menu scrolled within the viewport. Flick down from the top to dismiss.

Swipe to open

Swipe from the right edge of the frame (or drag it with a mouse) to open the drawer.

Swipe from the right edge to open the drawer.

Action sheet

An uncontained drawer with a separate destructive action, iOS style.

Styling

The engine drives CSS custom properties (registered with inherits: false) and data attributes; your stylesheet decides what they do.

CSS variables

  • --drawer-swipe-movement-x / -y — displacement during the drag, in px (on the popup)
  • --drawer-swipe-progress — 0–1, how far toward dismiss (on the backdrop)
  • --drawer-swipe-strength — 0.1–1, velocity scalar for the dismiss transition duration
  • --drawer-snap-point-offset — offset of the active snap point (on the popup)
  • --drawer-keyboard-inset — software keyboard inset (requires VirtualKeyboardProvider)
  • --nested-drawers — number of open nested drawers (for stacking effects)

Data attributes

  • [data-swiping] — present while the user is dragging
  • [data-expanded] — present when snapped to the largest snap point
  • [data-nested] / [data-nested-drawer-open] — nesting state, for stacked-cards styling
  • [data-starting-style] / [data-ending-style] — enter/exit transition hooks (from bits-ui)
  • [data-swipe-ignore] — opt-out: no swipe ever starts on this element
  • [data-swipe-ignore="x"] / ="y" — touch drags along that axis go to the element (e.g. a custom slider in a bottom drawer)

MIT © Jérémy Le Mardelé. Ported from Base UI (MIT © Material-UI SAS) — demos adapted from the Base UI documentation.