Drawer A bottom drawer with native-feeling drag-to-dismiss interaction. Built on vaul with snap points, multiple sizes, and composable slot components.
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.
Install the component via the CLI in one command.
npm pnpm yarn bun
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.
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm pnpm yarn bun
npm install @work-rjkashyap/unified-ui pnpm add @work-rjkashyap/unified-ui yarn add @work-rjkashyap/unified-ui bun add @work-rjkashyap/unified-ui
import {
Drawer,
DrawerTrigger,
DrawerContent,
DrawerHandle,
DrawerHeader,
DrawerBody,
DrawerFooter,
DrawerTitle,
DrawerDescription,
DrawerClose,
DrawerContent /* ... */ ,
} from "@work-rjkashyap/unified-ui" ;
<Drawer> <DrawerTrigger asChild> <Button variant="secondary">Open Drawer</Button> </DrawerTrigger> <DrawerContent> <DrawerHeader> <DrawerTitle>Edit Profile</DrawerTitle> <DrawerDescription>Make changes to your profile here.</DrawerDescription> </DrawerHeader> <DrawerBody> <Input placeholder="Name" /> </DrawerBody> <DrawerFooter> <Button>Save changes</Button> <DrawerClose asChild> <Button variant="secondary">Cancel</Button> </DrawerClose> </DrawerFooter> </DrawerContent> </Drawer>
<Drawer> <DrawerTrigger asChild> <Button>Small</Button> </DrawerTrigger> <DrawerContent size="sm">…</DrawerContent> </Drawer> <Drawer> <DrawerTrigger asChild> <Button>Medium</Button> </DrawerTrigger> <DrawerContent size="md">…</DrawerContent> </Drawer> <Drawer> <DrawerTrigger asChild> <Button>Large</Button> </DrawerTrigger> <DrawerContent size="lg">…</DrawerContent> </Drawer> <Drawer> <DrawerTrigger asChild> <Button>Full</Button> </DrawerTrigger> <DrawerContent size="full">…</DrawerContent> </Drawer>
<Drawer> <DrawerTrigger asChild> <Button>No Handle</Button> </DrawerTrigger> <DrawerContent showHandle={false}> <DrawerHeader> <DrawerTitle>No Handle</DrawerTitle> </DrawerHeader> <DrawerBody>Content</DrawerBody> <DrawerFooter> <DrawerClose asChild> <Button variant="secondary">Close</Button> </DrawerClose> </DrawerFooter> </DrawerContent> </Drawer>
Prop Type Default Description openboolean— Controlled open state. onOpenChange(open: boolean) => void— Callback 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() => void— Called when drawer is closed.
Prop Type Default Description size"sm" | "md" | "lg" | "full""md"Controls the maximum height of the drawer. showHandlebooleantrueWhether to show the drag handle indicator at the top. overlayClassNamestring— Extra classes for the backdrop overlay. classNamestring— Extra classes for the drawer content panel.
Prop Type Default Description asChildbooleanfalseMerge props onto the child element instead of rendering a <button>. classNamestring— Extra classes.
Prop Type Default Description asChildbooleanfalseMerge props onto the child element. classNamestring— Extra classes.
Prop Type Default Description classNamestring— Extra classes. childrenReactNode— Content.
Prop Type Default Description classNamestring— Extra classes. childrenReactNode— Text content.
Size Max Height Use Case sm30vhQuick confirmations, brief messages md50vhForms, moderate content (default) lg75vhLong forms, lists, rich content fullcalc(100vh - 2rem)Complex workflows, mobile-first views
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.
Token CSS Variable Tailwind Usage Background --backgroundbg-backgroundDrawer panel background Border --borderborder-borderPanel border Overlay — bg-black/50Backdrop overlay Z-index (content) --z-modalz-[var(--z-modal)]Drawer panel Z-index (overlay) --z-overlayz-[var(--z-overlay)]Backdrop Radius — rounded-t-lgTop corners only Shadow --shadow-xlshadow-xlElevation