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
98%
AGPL 3.0

Rybbit

Analytics

13,155

Open-source, privacy-friendly web and product analytics with cookieless tracking, session replays, funnels, and real-time dashboards — a self-hostable alternative to Google Analytics.

View details
87
Repo Health
85
Technical
68
Dependency
Built with
TypeScript 98%
Updated 6 days ago
TypeScript
98%
MIT

sigle

Blogging

489

A decentralized, open-source writing platform that permanently stores your stories on the Stacks blockchain and Arweave — where Web3 content creators own their words forever.

View details
81
Repo Health
78
Technical
69
Dependency
Built with
TypeScript 98%
Updated 2 weeks ago
Python
79%
AGPL 3.0

Skyvern

AI Agents · Automation

23,257

Skyvern (YC S2023) automates browser-based workflows by pairing LLMs with computer vision, letting agents click, fill, and extract data on sites they've never seen, without brittle XPath selectors that break on every layout change.

View details
89
Repo Health
82
Technical
70
Dependency
Built with
Python 79%
TypeScript 19%
Updated 6 days ago
TypeScript
96%
MIT

SplitPro

Invoicing Finance

1,474

Self-hosted, open source expense splitting with multi-currency, recurring bills, and bank imports — a complete Splitwise replacement you control.

View details
86
Repo Health
77
Technical
69
Dependency
Built with
TypeScript 96%
Updated 1 weeks ago
TypeScript
89%
Other

Hexclave

Authentication · Developer Tools

6,877

The open-source user infrastructure platform — authentication, teams, payments, emails, analytics, and more on a single unified user model.

View details
88
Repo Health
80
Technical
66
Dependency
Built with
TypeScript 89%
Updated 6 days ago
TypeScript
92%
Other

Suna

AI Agents

20,306

Turn your company into a git repo — one config, one command center, a workforce of AI agents that runs the real work around the clock.

View details
90
Repo Health
79
Technical
65
Dependency
Built with
TypeScript 92%
Updated 6 days ago
TypeScript
72%
Apache 2.0

Supabase

Authentication · Databases · Developer Tools

113,827

The open-source Postgres development platform that replaces Firebase with authentication, real-time APIs, edge functions, storage, and vector embeddings — all built on PostgreSQL.

View details
90
Repo Health
91
Technical
62
Dependency
Built with
TypeScript 72%
MDX 26%
Updated 6 days ago
TypeScript
48%
MIT

supermemory

AI Development · AI Memory · Note Taking

31,370

The state-of-the-art memory and context engine for AI agents — ranked #1 on all three major AI memory benchmarks.

View details
88
Repo Health
82
Technical
67
Dependency
Built with
TypeScript 48%
MDX 32%
Python 17%
Updated 6 days ago
TypeScript
85%
Apache 2.0

superset

AI Code Assistants · AI Development

15,503

Orchestrate an army of AI coding agents—Claude Code, Codex, Gemini CLI, and more—running simultaneously in isolated git worktrees from a single Electron desktop app.

View details
86
Repo Health
80
Technical
64
Dependency
Built with
TypeScript 85%
Updated 6 days 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