base-ui-vaul
v1.0.0
Published
Base UI implementation of Vaul — an unstyled drawer component for React 19.
Maintainers
Readme
base-ui-vaul
base-ui-vaul is the Base UI implementation of Vaul — an unstyled drawer component for React.
Vaul is built on Radix UI Dialog. This package keeps the same composable drawer API (Drawer.Root, Drawer.Content, snap points, drag-to-dismiss, nested drawers, and data-vaul-* styling hooks) while using @base-ui/react for dialog primitives. It targets React 19.
Installation
pnpm add base-ui-vaul @base-ui/react react react-domnpm install base-ui-vaul @base-ui/react react react-domyarn add base-ui-vaul @base-ui/react react react-dombun add base-ui-vaul @base-ui/react react react-domImport the default styles (or reimplement them with your own CSS):
import "base-ui-vaul/style.css";Peer dependencies
| Package | Version |
| --- | --- |
| react | ^19 |
| react-dom | ^19 |
| @base-ui/react | ^1 |
Quick start
import { Drawer } from "base-ui-vaul";
import "base-ui-vaul/style.css";
export function Example() {
return (
<Drawer.Root>
<Drawer.Trigger>Open drawer</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Handle />
<Drawer.Title>Title</Drawer.Title>
<Drawer.Description>Description</Drawer.Description>
<p>Drawer content</p>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}Migrating from Vaul
Replace the package import and add @base-ui/react as a peer dependency:
- import { Drawer } from "vaul"
+ import { Drawer } from "base-ui-vaul"- import "vaul/style.css"
+ import "base-ui-vaul/style.css"Component names and data-vaul-* attributes match Vaul so existing styles and behavior should carry over. Under the hood, Drawer uses Base UI Dialog (Root, Backdrop, Popup, Portal, Trigger, Close, Title, Description) instead of Radix.
Named exports are also available if you prefer not to use the namespace:
Root,Content,Overlay,Handle,Portal,NestedRootDialogProps,ContentProps,HandleProps
Snap points
import { Drawer } from "base-ui-vaul";
import "base-ui-vaul/style.css";
export function SnapPointsExample() {
return (
<Drawer.Root snapPoints={[0.25, 0.5, 0.75]} fadeFromIndex={2}>
<Drawer.Trigger>Open</Drawer.Trigger>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Handle />
{/* content */}
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}Controlled usage
const [open, setOpen] = React.useState(false);
<Drawer.Root open={open} onOpenChange={setOpen}>
{/* ... */}
</Drawer.Root>;API
Drawer namespace
| Part | Description |
| --- | --- |
| Drawer.Root | Drawer state, drag logic, snap points |
| Drawer.Trigger | Opens the drawer (Base UI Dialog.Trigger) |
| Drawer.Portal | Portals content (optional container) |
| Drawer.Overlay | Backdrop |
| Drawer.Content | Draggable panel |
| Drawer.Handle | Drag handle; double-tap cycles snap points |
| Drawer.Close | Close button |
| Drawer.Title / Drawer.Description | Accessibility labels |
| Drawer.NestedRoot | Nested drawer inside another |
Common Drawer.Root props
| Prop | Default | Description |
| --- | --- | --- |
| direction | "bottom" | "top" | "bottom" | "left" | "right" |
| dismissible | true | Allow drag / outside / Esc to close |
| modal | true | Modal focus trap and outside interaction |
| snapPoints | — | Heights as fractions (0.5) or px ("400px") |
| fadeFromIndex | last snap point | When overlay fade starts (required if using snapPoints with fade) |
| shouldScaleBackground | false | Scale page behind drawer |
| handleOnly | false | Only drag via Drawer.Handle |
| closeThreshold | 0.25 | Fraction dragged to close |
| onDrag / onRelease | — | Drag lifecycle callbacks |
| onAnimationEnd | — | Fires when open/close animation completes |
See exported DialogProps in TypeScript for the full list.
Styling
Default styles ship in base-ui-vaul/style.css. Target Vaul-compatible attributes:
[data-vaul-drawer][data-vaul-overlay][data-vaul-handle][data-vaul-drawer-direction="bottom"](andtop,left,right)
Opt out of drag on specific elements:
<div data-vaul-no-drag>No drag here</div>Wrap the page for background scaling:
<div data-vaul-drawer-wrapper>{/* app */}</div>Background scaling
<Drawer.Root shouldScaleBackground>
{/* ... */}
</Drawer.Root>Requires a [data-vaul-drawer-wrapper] ancestor around your main content.
Development
pnpm install
pnpm typecheck
pnpm buildPublishing
pnpm build
npm publishCredits
- Vaul by Emil Kowalski
- Base UI by MUI
License
MIT © nunesunil
