Drawer

A swipeable panel that opens from an edge of the screen.

Installation

npx shadcn@latest add @fulldev/drawer

Usage

import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"
<Drawer swipeDirection="down">
  <DrawerTrigger>Open</DrawerTrigger>
  <DrawerContent showSwipeHandle>
    <DrawerHeader>
      <DrawerTitle>Drawer title</DrawerTitle>
      <DrawerDescription>Drawer description</DrawerDescription>
    </DrawerHeader>
    <div class="p-4">Drawer content</div>
    <DrawerFooter>
      <DrawerClose variant="outline">Close</DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>

Composition

DrawerContent renders the required portal, backdrop, viewport, popup, and inner content structure. Use the lower-level exports when you need to customize that structure. Its inner content wrapper scrolls vertically when the panel contains more content than the available viewport.

Drawer
├── DrawerTrigger
└── DrawerContent
    ├── DrawerSwipeHandle
    ├── DrawerHeader
    │   ├── DrawerTitle
    │   └── DrawerDescription
    ├── content
    └── DrawerFooter
        └── DrawerClose

Examples

Directions

The swipe direction also chooses the edge where the drawer opens.

Nested

Place a complete Drawer inside another drawer’s content. Escape closes only the front drawer, then returns focus and interaction to its parent.

Non-modal

Pair a non-modal drawer with showOverlay={false} so controls outside the drawer remain visible and interactive.

modal="trap-focus" keeps keyboard focus inside the drawer without making the rest of the page inert. Also set showOverlay={false} when outside pointer interaction should remain available.

Snap point

One optional snap point controls how much of the panel is visible when open. A fraction uses the viewport size. Pixel numbers and px or rem strings are also supported.

Props and events

Drawer accepts defaultOpen, modal, disablePointerDismissal, closeOnEscape, swipeDirection, snapPoint, defaultSnapPoint, triggerId, and defaultTriggerId. DrawerContent accepts showOverlay, showSwipeHandle, container, keepMounted, initialFocus, and finalFocus.

Use the drawer:open, drawer:close, drawer:toggle, and drawer:set DOM events for imperative changes. The root emits cancelable drawer:beforechange and drawer:beforesnapchange events, followed by drawer:change, drawer:change-complete, and drawer:snapchange.

const drawer = document.querySelector('[data-slot="drawer"]')

drawer?.dispatchEvent(
  new CustomEvent("drawer:set", {
    detail: { open: true, snapPoint: "24rem" },
  })
)

API Reference

See the GitHub source code for component props. See the data-slot docs for controllers, events, focus management, detached triggers, nested drawers, and keyboard-aware viewports.