Drawer

A temporary side surface for focused work.

overlaysurface
Preview
Drawer preview

When to use

  • Side panels for filters, settings, or record details that keep the page in context.
  • Forms that are too long for a dialog but should not leave the current view.
  • Panels from any edge, via side, with drag-to-dismiss on the header.

When not to use

  • Use dialog for short decisions and confirmations.
  • Use bottom-sheet for mobile-first sheets with snap points.
  • Use popover for small anchored content that does not need a modal overlay.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "drawer",
  "type": "registry:ui",
  "title": "Drawer",
  "description": "A temporary side surface for focused work.",
  "categories": [
    "disclosure"
  ],
  "dependencies": [
    "@radix-ui/react-dialog",
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/drawer/drawer.tsx",
      "type": "registry:component",
      "target": "@components/manicat/drawer/drawer.tsx"
    },
    {
      "path": "registry/components/drawer/drawer.module.css",
      "type": "registry:component",
      "target": "@components/manicat/drawer/drawer.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/drawer",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/drawer",
    "markdown": "https://uiarc.dev/components/drawer/markdown",
    "tags": [
      "overlay",
      "surface"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { Drawer, DrawerClose, DrawerContent, DrawerTrigger } from "@/components/manicat/drawer/drawer";
import { Button } from "@/components/manicat/button/button";

export function DrawerExample() {
  return (
    <Drawer>
      <DrawerTrigger asChild>
        <Button variant="secondary">Open drawer</Button>
      </DrawerTrigger>
      <DrawerContent title="Filters" description="Narrow the list without leaving the page.">
        <p className="text-sm text-(color:--text-muted)">
          A drag on the edge closes the panel, handing its velocity to the exit spring.
        </p>
        <DrawerClose asChild>
          <Button>Show results</Button>
        </DrawerClose>
      </DrawerContent>
    </Drawer>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Filter drawer A side panel for secondary controls that keeps the list in view.

Filter drawer A side panel for secondary controls that keeps the list in view. preview

Keyboard interactions

KeysAction
EscapeCloses the drawer and returns focus to the trigger.
Tab / Shift+TabCycles focus within the panel while it is open.

Accessibility

  • Radix Dialog provides role="dialog", aria-modal, focus trapping, and focus return.
  • title and description are wired to Dialog.Title and Dialog.Description, so the panel is always named.
  • The header close button is labelled "Close drawer"; dragging is optional and never the only way to close.

Motion

  • The panel springs in from its edge and leaves faster on a tween; a drag past a third of the panel or a quick flick closes it and keeps the release velocity.
  • Dragging the header away from the edge rubber-bands; the overlay fades in and out.
  • Reduced motion disables dragging and replaces the slide with a short opacity fade.

Responsive behavior

  • Left and right panels are min(30rem, 100vw minus a gutter) wide; below 40rem they grow to nearly full width with tighter padding.
  • Top and bottom panels span the full width and cap at min(32rem, 100dvh).
  • The header is the drag handle with touch-action none, so a touch drag moves the panel while the body still scrolls normally.

Performance

  • The overlay uses a 4px backdrop blur, which can cost frames on low-end devices over busy pages.
  • Drag runs on motion pan handlers with no React re-render per frame; the panel stays mounted only while sliding out.

Notes for AI

  • Use for side panels with forms, filters, settings, or detail views that keep the page in context. Use dialog for short decisions and bottom-sheet for mobile-first sheets.
  • Always compose Drawer as the root; under a bare Radix Dialog root the panel falls back to CSS keyframes and loses drag.
  • Control open when the drawer must close after an async submit.