Unified UI

Drawer

A bottom drawer with native-feeling drag-to-dismiss interaction. Built on vaul with snap points, multiple sizes, and composable slot components.

Overview

The Drawer component is a bottom sheet overlay with drag-to-dismiss interaction. It slides up from the bottom of the viewport and can be dismissed by dragging down, pressing Escape, or clicking the overlay. Built on vaul for native-feeling touch interactions.


Installation

Install the component via the CLI in one command.

npx @work-rjkashyap/unified-ui add drawer
pnpm dlx @work-rjkashyap/unified-ui add drawer
npx @work-rjkashyap/unified-ui add drawer
bunx @work-rjkashyap/unified-ui add drawer

If you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.

Or install the full package

Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.

npm install @work-rjkashyap/unified-ui
pnpm add @work-rjkashyap/unified-ui
yarn add @work-rjkashyap/unified-ui
bun add @work-rjkashyap/unified-ui

Anatomy

import {
	Drawer,
	DrawerTrigger,
	DrawerContent,
	DrawerHandle,
	DrawerHeader,
	DrawerBody,
	DrawerFooter,
	DrawerTitle,
	DrawerDescription,
	DrawerClose,
	DrawerContent /* ... */,
} from "@work-rjkashyap/unified-ui";

Examples

Default

Sizes

Without Handle


Props

Drawer (Root)

PropTypeDefaultDescription
openbooleanControlled open state.
onOpenChange(open: boolean) => voidCallback when open state changes.
defaultOpenbooleanfalseWhether the drawer starts open.
shouldScaleBackgroundbooleantrueScale background content when open. Requires [vaul-drawer-wrapper] on your app wrapper.
dismissiblebooleantrueWhether the drawer can be dismissed by dragging or clicking outside.
direction"top" | "bottom" | "left" | "right""bottom"Direction the drawer opens from.
nestedbooleanfalseWhether this drawer is nested inside another drawer.
modalbooleantrueWhether to block body scroll when open.
onClose() => voidCalled when drawer is closed.

DrawerContent

PropTypeDefaultDescription
size"sm" | "md" | "lg" | "full""md"Controls the maximum height of the drawer.
showHandlebooleantrueWhether to show the drag handle indicator at the top.
overlayClassNamestringExtra classes for the backdrop overlay.
classNamestringExtra classes for the drawer content panel.

DrawerTrigger

PropTypeDefaultDescription
asChildbooleanfalseMerge props onto the child element instead of rendering a <button>.
classNamestringExtra classes.

DrawerClose

PropTypeDefaultDescription
asChildbooleanfalseMerge props onto the child element.
classNamestringExtra classes.

DrawerHeader / DrawerBody / DrawerFooter

PropTypeDefaultDescription
classNamestringExtra classes.
childrenReactNodeContent.

DrawerTitle / DrawerDescription

PropTypeDefaultDescription
classNamestringExtra classes.
childrenReactNodeText content.

Sizes Reference

SizeMax HeightUse Case
sm30vhQuick confirmations, brief messages
md50vhForms, moderate content (default)
lg75vhLong forms, lists, rich content
fullcalc(100vh - 2rem)Complex workflows, mobile-first views

Accessibility

  • Focus trap: Focus is trapped inside the drawer when open.
  • Escape to close: Pressing Escape closes the drawer.
  • Scroll lock: Body scroll is locked while the drawer is open.
  • ARIA: Uses role="dialog" with aria-labelledby (DrawerTitle) and aria-describedby (DrawerDescription) automatically via vaul.
  • Drag dismiss: The drawer can be swiped down to dismiss, providing a native-feeling interaction on touch devices.

Design Tokens

TokenCSS VariableTailwindUsage
Background--backgroundbg-backgroundDrawer panel background
Border--borderborder-borderPanel border
Overlaybg-black/50Backdrop overlay
Z-index (content)--z-modalz-[var(--z-modal)]Drawer panel
Z-index (overlay)--z-overlayz-[var(--z-overlay)]Backdrop
Radiusrounded-t-lgTop corners only
Shadow--shadow-xlshadow-xlElevation

On this page