Drawer
A panel that slides in from the edge of the screen with swipe gestures, snap points, and nested drawer support.
Drawer wraps the
Base UI Drawer primitive,
composes Button and its scrollable panel through Base UI's
render prop, and marks each part with data-slot. It is a client component:
it supports swipe gestures, snap points and nested drawers, uses a portal,
manages focus, and animates with tw-animate-css.
Installation
npx shadcn@latest add @kosori/drawerExample
drawer-example.tsx
import { Button } from '@/components/ui/button';
import {
Drawer,
DrawerClose,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerPanel,
DrawerPopup,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer';
const DrawerExample = () => (
<Drawer>
<DrawerTrigger render={<Button variant='outline' />}>
Nested drawers
</DrawerTrigger>
<DrawerPopup>
<DrawerHeader>
<DrawerTitle>First step</DrawerTitle>
<DrawerDescription>
This is the first step. Tap the button below to continue to the next
screen.
</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<DrawerClose render={<Button variant='ghost' />}>Cancel</DrawerClose>
<Drawer>
<DrawerTrigger render={<Button variant='outline' />}>
Continue
</DrawerTrigger>
<DrawerPopup>
<DrawerHeader>
<DrawerTitle>Second step</DrawerTitle>
<DrawerDescription>
You've reached the second step. Tap the button below to
continue to the next screen.
</DrawerDescription>
</DrawerHeader>
<DrawerPanel>
<div className='flex justify-center'>
<div className='size-48 shrink-0 rounded-xl border bg-muted' />
</div>
</DrawerPanel>
<DrawerFooter>
<DrawerClose render={<Button variant='ghost' />}>
Back
</DrawerClose>
<Drawer>
<DrawerTrigger render={<Button variant='outline' />}>
Continue
</DrawerTrigger>
<DrawerPopup>
<DrawerHeader>
<DrawerTitle>Third step</DrawerTitle>
<DrawerDescription>
You've reached the final step. You can close this
drawer or go back.
</DrawerDescription>
</DrawerHeader>
<DrawerPanel>
<div className='flex justify-center'>
<div className='size-32 shrink-0 rounded-full border bg-muted' />
</div>
</DrawerPanel>
<DrawerFooter>
<DrawerClose render={<Button variant='ghost' />}>
Close
</DrawerClose>
</DrawerFooter>
</DrawerPopup>
</Drawer>
</DrawerFooter>
</DrawerPopup>
</Drawer>
</DrawerFooter>
</DrawerPopup>
</Drawer>
);
export default DrawerExample;
Usage
import { Button } from '@/components/ui/button';
import {
Drawer,
DrawerClose,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerPopup,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer';
const DrawerDemo = () => (
<Drawer>
<DrawerTrigger render={<Button variant='outline' />}>
Open drawer
</DrawerTrigger>
<DrawerPopup>
<DrawerHeader>
<DrawerTitle>Edit profile</DrawerTitle>
<DrawerDescription>Make changes to your profile.</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<DrawerClose render={<Button variant='outline' />}>Cancel</DrawerClose>
<Button>Save changes</Button>
</DrawerFooter>
</DrawerPopup>
</Drawer>
);