Build · New

Drawer

A panel that slides up from the bottom of a phone screen for a short task or a list of actions, within thumb reach, with the page still visible behind it. Also known as a bottom sheet.

Preview

Mirrored is the same English content laid out right to left: it separates a mirroring bug from a translation one.

Installation

SoonInstalling from the registry opens at launch. Until then the command below is what it will be.
npx shadcn@latest add @ritla/drawer

Dependencies it brings: @base-ui/react, @phosphor-icons/react

Usage

import { Drawer, DrawerBody, DrawerContent, DrawerHeader, DrawerMenu, DrawerMenuItem, DrawerTrigger } from "@/components/ui/drawer";
<Drawer>
  <DrawerTrigger render={<Button />}>Move email</DrawerTrigger>
  <DrawerContent>
    <DrawerHeader title="Move to" />
    <DrawerBody>
      <DrawerMenu>
        <DrawerMenuItem leadingIcon={TrayIcon} onSelect={moveToInbox}>Inbox</DrawerMenuItem>
      </DrawerMenu>
    </DrawerBody>
  </DrawerContent>
</Drawer>

Examples

A short task

The content is one task (filters) ending with a secondary, then a primary button; the primary sits at the inline end. It holds choices, so a tap on the overlay doesn't close it (disablePointerDismissal).

A long list

The sheet stops at 90% of the screen and the content scrolls while the header stays. The subtitle sits beside the title.

Stacked actions

stacking="vertical" for long labels, primary on top. The buttons stay in reading order: secondary, then primary.

API reference

Drawer

PropTypeDefaultDescription
open / defaultOpen / onOpenChangebooleanControls whether it's open.
disablePointerDismissalbooleanfalseA tap on the overlay doesn't close it (sheets that hold input).

DrawerContent

PropTypeDefaultDescription
handlebooleantrueThe drag handle, a hint only.
initialFocusRefObject<HTMLElement>Where focus starts.

DrawerHeader

PropTypeDefaultDescription
titleReactNodeFigma's Title: what the sheet is for; it names the sheet.
subtitleReactNodeFigma's Subtitle, beside the title.
descriptionReactNodeFigma's Description: one short line of context.
badgeReactNodeFigma's Show badge: a count or short text.
closeButton / closeLabelboolean / stringtrue / "Close"The close button and its name. Keep it.

DrawerMenuItem

PropTypeDefaultDescription
childrenReactNodeThe row's text.
leadingIcon / description / trailingIconComponent / ReactNode / ReactNodeAn icon, a second line and a count at the end.
onSelect / disabled() => void / booleanRuns on tap; then the sheet closes.

DrawerActions / DrawerBody / DrawerMenuLabel / DrawerClose

PropTypeDefaultDescription
stacking"horizontal" | "vertical""horizontal"Figma's Stacking for the buttons.
DrawerBodydivThe content; it scrolls when needed.
DrawerMenuLabelh3Names a group of rows.
DrawerClose renderReactElementA button that closes the sheet.

Accessibility

Keyboard

Keys are written for left-to-right. In right-to-left the arrow keys swap: the one pointing toward the reading direction moves forward.

KeyAction
TabShift+TabBetween the sheet's controls only.
EscCloses it and returns focus to the button that opened it.

ARIA

  • The sheet is a dialog with aria-modal, named by its title.
  • Swiping down is never the only way to close: the close button (Close), Esc and the overlay.
  • The drag handle is decorative; rows and buttons are at least 48px.

Arabic and RTL notes

Mirrors

  • The title and menu icons sit on the right; the close button on the left.
  • The primary button moves to the left, at the inline end; the secondary to the right.

Does not mirror

  • The motion is vertical: it slides up and swipes down in both languages.
Numerals
Counts in rows follow the numerals setting; format them with formatNumber.
Arabic typography
Title label-14 Medium, subtitle and description label-12, rows as in the Menu.
Mixed-direction text
Names in another language inside rows get dir="auto".

All components ›