Vaul Drawer Reference

Vaul provides mobile-friendly drawers and bottom sheets with drag gestures, escape/outside dismissal, focus handling, portals, and smooth open/close behavior. Use it for drawers, bottom sheets, side sheets, and gesture-driven detail panels.

Overview

Use Vaul instead of hand-rolling drawers with fixed divs. For centered modal dialogs and destructive confirmations, use Radix Dialog or AlertDialog instead.

The examples below show only the structure and layout classes needed for a working drawer. Add local Tailwind styling that matches the app's visual language.

Import

import { Drawer } from 'vaul'

Bottom sheet

Good for mobile-first create/edit forms, item details, filters, and compact task flows.

import { Drawer } from 'vaul'

function BottomSheet() {
  return (
    <Drawer.Root>
      <Drawer.Trigger>Open sheet</Drawer.Trigger>
      <Drawer.Portal>
        <Drawer.Overlay className="fixed inset-0 z-40 bg-black/40" />
        <Drawer.Content className="fixed inset-x-0 bottom-0 z-50 max-h-[90vh] rounded-t-3xl bg-white p-4">
          <div className="mx-auto mb-4 h-1.5 w-12 rounded-full bg-gray-300" />
          <Drawer.Title>Edit item</Drawer.Title>
          <Drawer.Description>
            Make changes, then save when you're done.
          </Drawer.Description>
          <div className="mt-4 overflow-y-auto">Drawer content goes here.</div>
          <Drawer.Close>Close</Drawer.Close>
        </Drawer.Content>
      </Drawer.Portal>
    </Drawer.Root>
  )
}

Side drawer

Use side drawers for desktop inspector panels, detail panels, or focused editing while keeping the main app visible.

<Drawer.Root direction="right">
  <Drawer.Trigger>Open details</Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Overlay className="fixed inset-0 z-40 bg-black/40" />
    <Drawer.Content className="fixed bottom-0 right-0 top-0 z-50 flex w-full max-w-md flex-col bg-white p-4">
      <Drawer.Title>Item details</Drawer.Title>
      <Drawer.Description>
        Review context and update this item.
      </Drawer.Description>
      <div className="mt-6 min-h-0 flex-1 overflow-y-auto">
        Drawer content goes here.
      </div>
      <Drawer.Close>Close</Drawer.Close>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer.Root>

Best practices

  • Use Drawer.Root for interaction state and Drawer.Portal for overlay/content rendering.
  • Always include Drawer.Title; include Drawer.Description when a short explanation helps.
  • Use Drawer.Close for explicit close controls.
  • Bottom sheets should usually use rounded-t-*, a small drag handle, and max-h-[85vh] to max-h-[90vh].
  • Side drawers should use direction="left" or direction="right" and fill the viewport height.
  • Keep scroll inside the drawer body only when the drawer has an explicit max height or fixed height.
  • Use a full-screen drawer for immersive mobile editing flows when keeping context behind the drawer is not important.
  • Do not use Vaul for basic cards, inline panels, dropdown menus, or centered confirmation dialogs.