Skip to content

Now in the official shadcn registry directory.

Start free

Drawer

A draggable drawer on the vaul primitive - opens from any of the four edges, drags to dismiss, and shows a grab handle on the bottom direction.

overlay
A free styled version is available

Installation

Run the following command

npx shadcn@latest add @ai2/drawer

The vaul dependency, the @ai2/tokens theme and the component file are installed together.

Usage

TS
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

<Drawer>
  <DrawerTrigger asChild>
    <Button variant="outline">Open drawer</Button>
  </DrawerTrigger>
  <DrawerContent>
    <div className="mx-auto w-full max-w-sm">
      <DrawerHeader>
        <DrawerTitle>Deploy to production</DrawerTitle>
        <DrawerDescription>
          This promotes the current preview build to the live environment.
        </DrawerDescription>
      </DrawerHeader>
      <DrawerFooter>
        <Button tone="brand">Deploy</Button>
        <DrawerClose asChild>
          <Button variant="outline">Cancel</Button>
        </DrawerClose>
      </DrawerFooter>
    </div>
  </DrawerContent>
</Drawer>

Set direction on the Drawer root. The default bottom direction suits mobile sheets and shows the drag handle; use left or right for side panels.

Examples

Bottom with footer

The bottom direction renders the drag handle at the top of the panel; DrawerFooter pins its actions to the bottom edge and DrawerClose asChild dismisses without extra state.

Direction

Set direction to top, right, bottom or left. The right and left directions are full-height columns; only the bottom direction shows the drag handle.

Props

The Drawer root forwards every vaul prop; the props below are the ones you set most often.

PropTypeDefaultDescription
direction"top" | "right" | "bottom" | "left""bottom"Edge the drawer opens from, set on the Drawer root. Top and bottom are full-width panels capped at 80vh tall; left and right are full-height columns that are w-3/4 on mobile and capped at max-w-sm from the sm breakpoint up. The drag handle only renders on the bottom direction.
openbooleanundefinedControlled open state on the Drawer root. Pair with onOpenChange to drive the drawer from React state. Omit both for uncontrolled behavior via DrawerTrigger and DrawerClose.
onOpenChange(open: boolean) => voidundefinedCalled on the Drawer root whenever the open state changes, including drag-to-dismiss, Escape and overlay clicks.

ai2 Drawer: a draggable drawer for React on vaul

The ai2 Drawer is a shadcn-compatible drawer component for React, built on the vaul primitive and styled with Tailwind CSS v4. It is a panel that slides in from any of the four screen edges over a dimmed overlay and can be dragged to dismiss, ideal for mobile action sheets, filter panels, edit forms and detail views.

It ships through the shadcn registry format, so one CLI command, an MCP agent, or a copy-paste puts the source in your own project. You own the file; there is no runtime dependency on ai2 itself. The live example above is the exact component you get.

What is the ai2 Drawer?

It is a ten-part composition: Drawer, DrawerTrigger, DrawerContent, DrawerHeader, DrawerFooter, DrawerTitle, DrawerDescription, DrawerClose, DrawerOverlay and DrawerPortal. The anatomy matches shadcn/ui exactly, so existing snippets and AI agents keep working without changes.

Under the hood it is vaul: the panel renders in a portal over a fixed overlay and responds to a drag gesture, so a user can flick it away as well as press Escape or click the overlay. The one styling decision you make is the direction prop on the root, which anchors the drawer to the top, right, bottom or left edge. The bottom direction renders a rounded drag handle at the top of the panel.

Why use it

  • Four directions from one prop: direction="bottom" (the default), top, left or right, set on the Drawer root. Top and bottom are full-width panels capped at 80vh; left and right are full-height columns capped at max-w-sm from the sm breakpoint up.
  • Drag to dismiss: vaul tracks the drag gesture so the drawer follows the pointer and closes when flicked past the threshold. The bottom direction shows a grab handle so the affordance is obvious.
  • Accessible by construction: vaul builds on a dialog pattern: it traps focus while open, wires the accessible name through DrawerTitle and the description through DrawerDescription, closes on Escape and returns focus to the trigger.
  • Header and footer slots: DrawerHeader stacks the title and description and centers them on the top and bottom directions; DrawerFooter uses mt-auto to pin actions to the far edge of the panel.
  • Controlled or uncontrolled: Let DrawerTrigger manage the open state, or pass open and onOpenChange to the root to drive the drawer from router state or a keyboard shortcut.

Features

  • shadcn registry install: One command adds the component, the vaul dependency and the @ai2/tokens theme to your project.
  • Directional layout: Each direction sets its own inset, radius and border via data-vaul-drawer-direction attributes, so one component covers edge panels and bottom sheets alike.
  • Bottom drag handle: A rounded bar renders at the top of the panel only on the bottom direction, marking the drawer as draggable without extra markup.
  • Portal rendering: The overlay and panel render in a portal at z-50, so the drawer escapes any overflow or stacking context in the surrounding layout.
  • Data attributes for styling: Every part exposes data-slot, and the panel exposes data-vaul-drawer-direction and data-state, so you can restyle direction and open state from CSS without forking the component.
  • TypeScript source: The file you install is typed end to end and forwards every vaul prop, so autocomplete covers the full API.

Production tips

  • Always include DrawerTitle: The title is what the drawer announces as its accessible name. For a visually clean panel, keep the title and hide it with sr-only instead of omitting it.
  • Match direction to the use case: Bottom suits mobile action and filter sheets, right and left suit detail panels and navigation, top works best for short announcements. Only the bottom direction shows the drag handle.
  • Constrain the inner width: For the bottom direction, wrap the header and footer in a mx-auto w-full max-w-sm div so the content stays readable on wide screens while the panel spans the full width.
  • Use DrawerClose for cancel actions: Wrap your Cancel button in DrawerClose asChild instead of wiring onOpenChange manually. It dismisses the drawer and keeps focus management intact.
  • Prefer the bottom sheet on mobile: The drag-to-dismiss gesture reads most naturally on a bottom sheet, which is why the drag handle is reserved for that direction.

Works with the rest of ai2

The drawer composes naturally with the rest of the registry. Use an ai2 Button as the trigger and for footer actions, lay out edit forms inside with ai2 Field and ai2 Input rows, and divide long panels with an ai2 Separator.

When the surface should sit in the center of the screen instead of an edge, reach for Dialog. When you want an edge panel without the drag gesture, the Sheet shares the same anatomy on the radix Dialog primitive. Everything reads one token source, so combinations stay consistent in both light and dark mode.

FAQs

Get new components in your inbox

Component drops, new themes and release notes. No spam, and you can unsubscribe from any email.

© 2026 ai2 design system · MIT licensed · Built with its own components