Snap-point drawers for React.
- 🎯 Physics-based animations - Smooth spring physics instead of CSS transitions
- 📱 Mobile-first - Optimized touch gestures and performance
- ♿️ Accessible - WCAG 2.1 AA compliant with full keyboard support
- 🎨 Highly customizable - Comprehensive theming and styling options
- 📦 Tiny bundle - Tree-shakeable, ~4KB gzipped
- 🔧 Framework agnostic core - Built on a framework-independent engine
- ⚡️ Blazing fast - Optimized rendering and gesture handling
- 🧪 Well tested - 100% test coverage with unit and E2E tests
- 🔒 Type-safe - Full TypeScript support with strict mode
This monorepo contains:
- @studioantipodes/detent - React bindings for the drawer component
- @studioantipodes/detent-core - Framework-agnostic core engine
npm install @studioantipodes/detent
# or
pnpm add @studioantipodes/detent
# or
yarn add @studioantipodes/detentimport { Drawer } from '@studioantipodes/detent';
function App() {
return (
<Drawer.Root>
<Drawer.Trigger>Open Drawer</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Title>My Drawer</Drawer.Title>
<Drawer.Description>This is a drawer component</Drawer.Description>
<p>Your content here</p>
<Drawer.Close>Close</Drawer.Close>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}For detailed documentation, see:
- React Package README - Full API reference and examples
- Core Package README - Framework-agnostic core
- Contributing Guide - How to contribute
- Implementation Guide - Complete implementation details
import { useState } from 'react';
import { Drawer } from '@studioantipodes/detent';
function ControlledDrawer() {
const [open, setOpen] = useState(false);
return (
<Drawer.Root open={open} onOpenChange={setOpen}>
<Drawer.Trigger>Open</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<p>Controlled drawer</p>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}<Drawer.Root direction="top">...</Drawer.Root>
<Drawer.Root direction="left">...</Drawer.Root>
<Drawer.Root direction="right">...</Drawer.Root>
<Drawer.Root direction="bottom">...</Drawer.Root> {/* default */}<Drawer.Root>
<Drawer.Trigger>Open</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content snapPoints={[0.5, 0.8, 1]}>
<p>Drawer with snap points at 50%, 80%, and 100%</p>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root><Drawer.Root modal={true}>
<Drawer.Trigger>Open Modal Drawer</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<p>This drawer locks scroll and traps focus</p>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>- Node.js >= 18.0.0
- pnpm >= 8.0.0
# Clone the repository
git clone https://github.com/romainvalla/detent.git
cd detent
# Install dependencies
pnpm install
# Build all packages
pnpm run build
# Run tests
pnpm run test
# Start development mode
pnpm run dev
# Start playground
pnpm run playground:devpnpm run build- Build all packagespnpm run dev- Development mode for all packagespnpm run test- Run all testspnpm run test:e2e- Run Playwright E2E testspnpm run lint- Lint all packagespnpm run type-check- TypeScript type checkingpnpm run format- Format code with Biome
detent/
├── packages/
│ ├── core/ # Framework-agnostic core engine
│ └── react/ # React bindings
├── apps/
│ └── playground/ # Development playground
├── e2e/ # E2E tests with Playwright
└── .github/
└── workflows/ # CI/CD pipelines
Detent is inspired by vaul but offers significant improvements:
- Vaul is currently unmaintained
- Detent is actively developed and maintained
- Spring physics for more natural animations
- Automatic optimizations with ResizeObserver
- Smaller bundle size (~4KB vs ~8KB)
- Framework-agnostic core works with React, Vue, Solid (coming soon)
- Easier to add support for new frameworks
- Full TypeScript strict mode support
- Comprehensive type definitions for all APIs
- 100% test coverage vs ~60% in vaul
- Comprehensive E2E tests with Playwright
- Mobile device simulation
- Built with modern tools: Biome, Vitest, Turbo, Changesets
- Better developer experience
- Faster builds and tests
- Custom accessibility implementation
- Not dependent on external UI libraries
- Full WCAG 2.1 AA compliance
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
- Mobile browsers (iOS Safari, Chrome on Android)
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Create a changeset:
pnpm changeset - Submit a pull request
MIT © Detent
See LICENSE for details.
- Inspired by vaul by Emil Kowalski
- Built with modern React patterns and best practices
- Uses spring physics similar to iOS and Android native animations
- GitHub Issues - Bug reports and feature requests
- GitHub Discussions - Questions and community discussions
Note: This library is currently in active development. The API is stable, but minor breaking changes may occur before the 1.0 release. We use semantic versioning and changesets to manage releases transparently.