Drawer
A panel that slides in from the start, end, top or bottom of the screen (DGA: Slideout Menu). White or gray, closes by swipe, and flips with the page direction.
Version 0.4.1 ·
Installation
bunx --bun shadcn@latest add @dga/drawerUsage
import { Button } from "@/components/ui/button";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer";
export function FilterDrawer() {
return (
<Drawer side="start">
<DrawerTrigger render={<Button variant="outline" />}>Filter</DrawerTrigger>
<DrawerContent closeLabel="Close">
<DrawerHeader>
<DrawerTitle>Filter</DrawerTitle>
<DrawerDescription>Choose what appears in the request list.</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<DrawerClose render={<Button />}>Apply</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
}Use a Drawer for content that sits beside the page and should not leave it: a navigation menu on a phone, filters, a details panel. For a decision that must be answered, use a Dialog. side is start, end, top or bottom. start and end follow the page direction, so a start drawer is on the left in English and on the right in Arabic, and swiping toward that edge closes it. Give it a DrawerTitle.
Anatomy
- Backdrop: dims the page and makes it inert.
- Content: the panel, 346px wide on the sides and full width at the top or bottom. White (
background-menu) or gray (neutral-100). - Header: DrawerTitle and DrawerDescription.
- Footer: DrawerFooter, pushed to the bottom, with the actions on the end side.
- Close button: in the corner, on the end side.
Examples
Sides
The four sides. Open the first one in each direction and compare where it appears.
Navigation
The gray tone, a start drawer with a list of links. Links are ordinary buttons that render an <a>.
Controlled, without the corner button
Pass open and onOpenChange to open the drawer from your own code, and set showCloseButton={false} when the footer already has a close action. Escape and a click on the page behind still close it.
RTL
start and end swap: the same drawer slides in from the right on Arabic pages, with its border on the left, and a swipe toward the right closes it. The slide animation mirrors with it.
Accessibility
| Key | Action |
|---|---|
| Tab | Moves focus to the next control inside the drawer. Focus stays inside. |
| Shift + Tab | Moves focus back. |
| Escape | Closes the drawer and returns focus to the control that opened it. |
- Built on Base UI Drawer: a modal dialog with
aria-labelledbyandaria-describedby. The page behind is inert and its scroll is locked. - Focus is trapped inside and returns to the trigger on close. Swiping is an extra way to close it, never the only one.
- The close button has an accessible name (
closeLabel). Text and icons are 4.5:1 and 3:1 or better on the white and gray surfaces, in light and dark. - With reduced motion the drawer appears without sliding.
API Reference
Drawer
A panel that slides in from an edge of the screen (DGA: Slideout Menu). It is a modal dialog: focus is trapped inside, Escape closes it and focus returns to the trigger. On touch screens it can be swiped closed.
| Prop | Type | Default |
|---|---|---|
"start" | "end" | "top" | "bottom"The edge the drawer slides in from. `start` and `end` follow the page direction, so a `start` drawer is on the right on Arabic pages. Closing by swipe follows it. | "end" | |
| ||
booleanWhether the drawer is initially open. To render a controlled drawer, use the `open` prop instead. | No default | |
| ||
(open: boolean) => voidEvent handler called when the drawer is opened or closed. | No default | |
| ||
booleanWhether the drawer is currently open. | No default | |
| ||
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerClose
Closes the drawer. Render a Button with it: `<DrawerClose render={<Button />}>`.
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerContent
The panel: a dimmed backdrop and the card, 346px wide on the sides and full width at the top or bottom.
| Prop | Type | Default |
|---|---|---|
"white" | "gray"Surface: `white` (background-menu) or `gray` (neutral-100). | "white" | |
| ||
booleanShows the close button in the corner. | true | |
| ||
stringAccessible name of the close button. Translate it on Arabic pages. | "Close" | |
| ||
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerDescription
Explains the drawer. Linked to it with `aria-describedby`.
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerFooter
The actions at the bottom of the panel, aligned to the end.
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerHeader
Groups the title and description at the top of the panel.
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerTitle
The name of the drawer. Screen readers announce it when the drawer opens.
Also accepts every prop of the Base UI Drawer (opens in a new tab).
DrawerTrigger
The button that opens the drawer.
Also accepts every prop of the Base UI Drawer (opens in a new tab).
Deviations from DGA
- Figma's Slideout Menu is a 346px panel that is part of the layout. This is a modal drawer: focus trap, Escape and swipe. The side panel in your layout is a navigation list, not this.
- The border next to the page is logical (
border-eorborder-s). DGA'sborder-rightand slide direction are physical, so they would be on the wrong side in Arabic.
| Change | Reason |
|---|---|
Drawer: from Slideout Menu to a modal drawer | A panel that covers the page needs the same focus trap and Escape as a dialog. DGA's border-right and its slide direction are physical, so they would be on the wrong side in Arabic. |
Contrast
20 pairs checked · all pass WCAG 2.1 AAShow 10 statesHide
| Variant / state | Light | Dark |
|---|---|---|
| white / title | 14.53:1 AAA | 14.42:1 AAA |
| white / description | 10.17:1 AAA | 10.95:1 AAA |
| white / body text | 18.09:1 AAA | 14.42:1 AAA |
| white / close icon | 18.09:1 3:1 | 14.42:1 3:1 |
| white / focus ring | 18.09:1 3:1 | 15.89:1 3:1 |
| gray / title | 13.20:1 AAA | 14.42:1 AAA |
| gray / description | 9.24:1 AAA | 10.95:1 AAA |
| gray / body text | 16.44:1 AAA | 14.42:1 AAA |
| gray / close icon | 16.44:1 3:1 | 14.42:1 3:1 |
| gray / focus ring | 16.44:1 3:1 | 15.89:1 3:1 |
Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report