Skip to content

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 ·

Drawer sides

Installation

bunx --bun shadcn@latest add @dga/drawer

Usage

page.tsx
tsx
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.

Sides

The gray tone, a start drawer with a list of links. Links are ordinary buttons that render an <a>.

Navigation

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.

Controlled

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.

LTR (English)
RTL (Arabic)

Accessibility

KeyAction
TabMoves focus to the next control inside the drawer. Focus stays inside.
Shift + TabMoves focus back.
EscapeCloses the drawer and returns focus to the control that opened it.
  • Built on Base UI Drawer: a modal dialog with aria-labelledby and aria-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.

Drawer props
PropTypeDefault
"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"
boolean

Whether the drawer is initially open. To render a controlled drawer, use the `open` prop instead.

No default
(open: boolean) => void

Event handler called when the drawer is opened or closed.

No default
boolean

Whether 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.

DrawerContent props
PropTypeDefault
"white" | "gray"

Surface: `white` (background-menu) or `gray` (neutral-100).

"white"
boolean

Shows the close button in the corner.

true
string

Accessible 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-e or border-s). DGA's border-right and slide direction are physical, so they would be on the wrong side in Arabic.
ChangeReason
Drawer: from Slideout Menu to a modal drawerA 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.

View all 1 deviations for this component

Contrast

20 pairs checked · all pass WCAG 2.1 AAShow 10 states
Variant / stateLightDark
white / title14.53:1 AAA14.42:1 AAA
white / description10.17:1 AAA10.95:1 AAA
white / body text18.09:1 AAA14.42:1 AAA
white / close icon18.09:1 3:114.42:1 3:1
white / focus ring18.09:1 3:115.89:1 3:1
gray / title13.20:1 AAA14.42:1 AAA
gray / description9.24:1 AAA10.95:1 AAA
gray / body text16.44:1 AAA14.42:1 AAA
gray / close icon16.44:1 3:114.42:1 3:1
gray / focus ring16.44:1 3:115.89:1 3:1

Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report