Vaul

An unstyled, physics-based drawer component for React, built on Radix UI's Dialog primitive.

Library
npm
v1.1.2
8,649 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
48 /100 Fair
Development Activity 0
Maintenance 44
Community 56
Maturity 52
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
74 /100 Good
Architecture 78
Code Quality 72
Innovation 82
Learning Curve 65

Vaul is a React component library for building drawers — bottom sheets, side panels, and swipeable overlays — modeled after the drawer interaction popularized by iOS. It wraps Radix UI’s Dialog primitive with pointer-based drag tracking, velocity-aware snap points, and background scaling so the resulting drawer feels physically responsive rather than purely CSS-animated.

The library ships as a small set of composable components (Root, Trigger, Content, Overlay, Handle, NestedRoot, Portal) that mirror Radix’s own API shape, and it is unstyled by default, leaving all visual styling to the consuming application while vaul handles the gesture physics, focus management, and scroll-locking behavior.

What You Get

  • Drawer.Root/Trigger/Content/Overlay/Handle/NestedRoot components with a Radix-like compound API
  • Pointer-based drag tracking with velocity thresholds, dampening, and directional (top/bottom/left/right) support
  • Configurable snap points (percentage or pixel) with fade-from-index background overlay control
  • Built-in scroll locking, iOS Safari viewport/keyboard handling, and background scaling on open
  • Nested drawer support via Drawer.NestedRoot for stacked sheet flows

Common Use Cases

  • Mobile-style bottom sheets for menus, filters, or action lists in a responsive web app
  • Side-panel drawers for cart, settings, or detail views triggered by a click
  • Multi-step snap-point sheets, e.g. a half-open preview that expands to full height
  • shadcn/ui-style drawer components layered on top of Radix + Tailwind design systems

Under The Hood

Architecture — Vaul is a single-package React component library (~2,300 lines across 12 TS/TSX files under src/) that wraps Radix UI’s Dialog primitive (DialogPrimitive.Root/Content/Overlay/Trigger/Portal/Close/Title/Description) with pointer-event-based drag physics. The core Root component (src/index.tsx) owns all interaction state (isDragging, activeSnapPoint, drawer/overlay refs) via React state and refs, and exposes it through a DrawerContext (src/context.ts) that Content/Overlay/Handle subcomponents consume via useDrawerContext(). Dragging is handled with native pointer events rather than a gesture library, translating the drawer’s DOM node directly via CSS transforms (helpers.ts: set/getTranslate/dampenValue) for smooth movement, then handing off to Radix’s own open/close state machine on release. Snap points are computed as a separate concern in use-snap-points.ts, converting percentage/pixel snap definitions into pixel offsets relative to the window or a custom container, and deciding on release whether to snap to the nearest point or fling based on velocity thresholds. Two hooks handle platform quirks: use-position-fixed.ts works around iOS Safari’s viewport/scroll bugs by pinning body position while a modal drawer is open, and use-prevent-scroll.ts (adapted from Adobe’s react-spectrum) blocks background touch-scrolling on iOS during drag.

Tech Stack — TypeScript (96% of the codebase) targeting React 16.8 through 19 as peer dependencies, with a single runtime dependency: @radix-ui/react-dialog (^1.1.1), which supplies accessible dialog semantics (focus trap, ARIA, escape-to-close) that Vaul layers drag/snap behavior on top of. The package is built with bunchee into dual ESM/CJS output with generated .d.ts files, and the monorepo uses pnpm workspaces + Turborepo to coordinate the library package and a separate test/ Next.js app used for Playwright e2e tests. Styling ships as a small style.css file for defaults rather than a CSS-in-JS runtime, keeping the library unopinionated about the consumer’s styling approach.

Code Quality — There is a real, if end-to-end rather than unit, test suite: test/tests/*.spec.ts uses Playwright against a dedicated Next.js app covering base behavior, controlled mode, nested drawers, snap points, scaled/unscaled backgrounds, non-dismissible drawers, and handle interactions — a meaningful signal given how gesture-heavy this code is. Source files are consistently typed with explicit prop interfaces (DialogProps, HandleProps, ContentProps) and use React.forwardRef correctly, though several internal call sites use @ts-ignore and any casts around vendor-prefixed CSS properties and a WeakMap-cached style object in helpers.ts. Naming is consistent and descriptive, but the core Root component in index.tsx is a single ~700-line function with many closures and refs, concentrating most of the library’s complexity in one file. Error handling is minimal by design, with most edge cases guarded by early-return checks and one explicit thrown Error in NestedRoot for genuine misuse (nesting outside a parent drawer).

API Design — The public API is a small, Radix-shaped compound-component object (Drawer.Root, .Trigger, .Content, .Overlay, .Handle, .NestedRoot, .Portal, .Close, .Title, .Description) that developers already familiar with Radix Dialog or shadcn/ui can pick up with near-zero new concepts — Trigger/Close/Title/Description are literally re-exported from @radix-ui/react-dialog. A basic drawer needs only a trigger and content wrapped in Root, with sensible defaults (modal=true, dismissible=true, direction=‘bottom’) covering the common case, while advanced behavior (snap points, custom container, handle-only dragging, fade-from-index) is opt-in via JSDoc comments directly on each prop that double as inline editor documentation. The main weakness is that project-level documentation lives almost entirely outside the repo, on the official docs site, since the README is now reduced to a single unmaintained-status notice — so newcomers exploring the repo itself have to read prop JSDoc and the Playwright tests to understand behavior.

Used by 49 apps in this directory

TypeScript
99%
Apache 2.0

Onlook

AI Design Tools · Design Tools

26,996

An open-source, AI-first visual editor that lets designers and developers build, style, and deploy React apps directly in code — no handoff required.

View details
63
Repo Health
80
Technical
64
Dependency
Built with
TypeScript 99%
Updated 1 weeks ago
TypeScript
99%
MIT

open-agents

AI Agents · Developer Tools

5,861

Open-source reference app for building and running background AI coding agents on Vercel — from chat prompt to committed code changes without keeping your laptop involved.

View details
41
Repo Health
78
Technical
73
Dependency
Built with
TypeScript 99%
Updated 2 months ago
TypeScript
82%
AGPL 3.0

OpenStatus

Devops · Monitoring

9,221

Open-source status pages and uptime monitoring with global synthetic checks, monitoring-as-code, and AI agent integration via MCP.

View details
77
Repo Health
82
Technical
69
Dependency
Built with
TypeScript 82%
MDX 14%
Updated 1 weeks ago
TypeScript
84%
MIT

OpenCut

Design Tools · Social Media · Video Editors

95,947

Free, open-source video editor for web, desktop, and mobile — no watermarks, no subscriptions, built with a Rust core and plugin-first architecture

View details
55
Repo Health
67
Technical
77
Dependency
Built with
TypeScript 84%
Rust 14%
Updated 1 months ago
TypeScript
93%
Apache 2.0

Openship

Devops · Hosting Control Panel

14,912

Openship is an open-source, self-hostable deployment platform that points at a repo and builds, ships, routes, and TLS-terminates the app — driven from a desktop app, web dashboard, or CLI.

View details
84
Repo Health
85
Technical
65
Dependency
Built with
TypeScript 93%
Updated 6 days ago
TypeScript
98%
Other

Outline

Collaboration · Knowledge Management

41,045

A fast, real-time collaborative knowledge base for growing teams built on React, Node.js, and ProseMirror.

View details
91
Repo Health
87
Technical
68
Dependency
Built with
TypeScript 98%
Updated 6 days ago
TypeScript
99%
AGPL 3.0

Pangolin

Networking

23,187

An open-source, identity-based zero-trust remote access platform built on WireGuard — a self-hostable alternative to Cloudflare Tunnel and Twingate with SSO, OIDC, and tunneled reverse proxying.

View details
87
Repo Health
68
Technical
68
Dependency
Built with
TypeScript 99%
Updated 1 weeks ago
TypeScript
99%
Other

Papermark

Digital Signiture · File Storage

9,263

Open-source DocSend alternative with page-by-page analytics, secure data rooms, and custom domains for document sharing.

View details
78
Repo Health
63
Technical
66
Dependency
Built with
TypeScript 99%
Updated 2 months ago
TypeScript
99%
MIT

Rudel

Developer Tools

306

Open-source analytics for Claude Code and Codex sessions — a CLI uploads session transcripts to a self-hostable dashboard tracking token usage, session duration, activity patterns, and model usage.

View details
75
Repo Health
67
Technical
71
Dependency
Built with
TypeScript 99%
Updated 2 weeks ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers