A bottom sheet you can drag down to dismiss.
import {
Drawer,
DrawerTrigger,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
DrawerClose,
} from '@/components/ui/drawer'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
export default function DrawerDemo() {
return (
<Drawer>
<DrawerTrigger render={<Button variant="outline">Open drawer</Button>} />
<DrawerContent>
<DrawerHeader>
<DrawerTitle>New project</DrawerTitle>
<DrawerDescription>Give it a name. Drag the handle down, or press Escape, to dismiss.</DrawerDescription>
</DrawerHeader>
<div className="mt-4 grid gap-1.5">
<Label htmlFor="drawer-name">Project name</Label>
<Input id="drawer-name" placeholder="Reading room" />
</div>
<DrawerFooter>
<DrawerClose render={<Button>Create project</Button>} />
<DrawerClose render={<Button variant="outline">Cancel</Button>} />
</DrawerFooter>
</DrawerContent>
</Drawer>
)
}
Built on Base UI
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/drawer.jsonNeeds a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.
Drawer imports cn() from lib/utils.ts — add it too if you don't have it yet:
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Usage
import {
Drawer,
DrawerTrigger,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
DrawerClose,
} from '@/components/ui/drawer'
import { Button } from '@/components/ui/button'
<Drawer>
<DrawerTrigger render={<Button variant="outline">Open drawer</Button>} />
<DrawerContent>
<DrawerHeader>
<DrawerTitle>New project</DrawerTitle>
<DrawerDescription>Give it a name.</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<DrawerClose render={<Button variant="outline">Cancel</Button>} />
</DrawerFooter>
</DrawerContent>
</Drawer>Examples
Scrollable content
import {
Drawer,
DrawerTrigger,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
DrawerClose,
} from '@/components/ui/drawer'
import { Button } from '@/components/ui/button'
const notes = Array.from({ length: 14 }, (_, i) => ({
version: `1.${14 - i}.0`,
text: 'Smaller bundles, steadier focus handling and a handful of visual fixes.',
}))
export default function DrawerScrollable() {
return (
<Drawer>
<DrawerTrigger render={<Button variant="outline">Release notes</Button>} />
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Release notes</DrawerTitle>
<DrawerDescription>The drawer stops at 85% of the screen and scrolls when its content is longer.</DrawerDescription>
</DrawerHeader>
<ul className="mt-4 grid gap-4">
{notes.map(note => (
<li key={note.version} className="grid gap-1 border-b border-border pb-4 last:border-b-0">
<span className="text-sm font-medium">v{note.version}</span>
<span className="text-sm text-muted-foreground">{note.text}</span>
</li>
))}
</ul>
<DrawerFooter>
<DrawerClose render={<Button variant="outline">Close</Button>} />
</DrawerFooter>
</DrawerContent>
</Drawer>
)
}
API Reference
| Name | Type | Default | Description |
|---|---|---|---|
| open / onOpenChange | boolean / (open: boolean) => void | — | Control the open state from outside (set on Drawer). |
| defaultOpen | boolean | false | Initial open state (uncontrolled). |
| modal | boolean | 'trap-focus' | true | Traps focus and locks page scroll while open. |
| disablePointerDismissal | boolean | false | Stops outside clicks from closing the drawer. |
| DrawerTrigger render | ReactElement | — | Renders the trigger as a different element, e.g. a Button. |
| DrawerClose render | ReactElement | — | Renders a close control as a different element. |
| Dismissing | — | — | Drag the sheet down (mouse, touch or pen), press Escape, click the backdrop, or use a DrawerClose. Focus returns to the trigger. |
| DrawerContent | — | — | A bottom sheet with a handle bar, capped at 85% of the screen height; its content scrolls when longer. For other edges use Sheet. |