Drawer

A panel that slides in from the edge of the screen with swipe-to-dismiss gestures.

Anatomy

Import and assemble the component:

1import { Drawer } from "@raystack/apsara";
2
3<Drawer side="right">
4 <Drawer.Trigger />
5 <Drawer.Content side="right">
6 <Drawer.Header>
7 <Drawer.Title />
8 <Drawer.Description />
9 </Drawer.Header>
10 <Drawer.Body />
11 <Drawer.Footer />
12 </Drawer.Content>
13</Drawer>

Usage

Pick the edge it enters from, then decide who owns its open state.

Basic

A drawer slides in from the edge named by the side of Drawer.Content and traps focus while open.

1<Drawer side="right">
2 <Drawer.Trigger render={<Button />}>Open Drawer</Drawer.Trigger>
3 <Drawer.Content>
4 <Drawer.Header>
5 <Drawer.Title>Drawer Title</Drawer.Title>
6 <Drawer.Description>Drawer description goes here</Drawer.Description>
7 </Drawer.Header>
8 <Drawer.Body>
9 <span>Main content of the drawer</span>
10 </Drawer.Body>
11 </Drawer.Content>
12</Drawer>

Positioning

The Drawer can slide in from different sides of the screen. Swipe-to-dismiss is automatically configured based on the side prop.

1<Flex gap={5}>
2 <Drawer side="top">
3 <Drawer.Trigger render={<Button />}>Top Drawer</Drawer.Trigger>
4 <Drawer.Content side="top">
5 <Drawer.Header>
6 <Drawer.Title>Top Drawer</Drawer.Title>
7 <Drawer.Description>Slides in from the Top</Drawer.Description>
8 </Drawer.Header>
9 <Drawer.Body>Content here</Drawer.Body>
10 </Drawer.Content>
11 </Drawer>
12 <Drawer side="right">
13 <Drawer.Trigger render={<Button />}>Right Drawer</Drawer.Trigger>
14 <Drawer.Content side="right">

Controlled

Pass open with onOpenChange to own the state. Do this when the drawer has to open from elsewhere on the page, or stay open until a save completes.

1(function ControlledDrawer() {
2 const [open, setOpen] = React.useState(false);
3
4 return (
5 <Flex align="center" gap={5}>
6 <Button variant="outline" onClick={() => setOpen(true)}>
7 Open from outside
8 </Button>
9 <Drawer open={open} onOpenChange={setOpen} side="right">
10 <Drawer.Content>
11 <Drawer.Header>
12 <Drawer.Title>Settings</Drawer.Title>
13 </Drawer.Header>
14 <Drawer.Body>

API Reference

The same header, body and footer shell as Dialog, anchored to an edge.

Root

Groups all parts of the drawer. Its side prop sets the swipe-to-dismiss direction. Drawer.Content has its own side, which places the panel. Set both to the same edge.

Prop

Type

Trigger

Renders the button that opens the drawer.

  • Inherits all Base UI Drawer.Trigger props

Close

Renders a button that closes the drawer. Drawer.Content already renders one unless showCloseButton is false.

  • Inherits all Base UI Drawer.Close props

Content

Renders the drawer panel that slides in from a screen edge.

Prop

Type

  • children: React.ReactNode - Content to render inside the header
  • className: string - Additional CSS class name

Title

  • Inherits all Base UI Drawer.Title props

Description

  • Inherits all Base UI Drawer.Description props

Body

  • Inherits all HTML div element props
  • Inherits all HTML div element props

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
drawer-backdropThe overlay behind the drawer
drawer-viewportViewport wrapper that positions the drawer
drawer-contentThe drawer panel (popup)
drawer-content-bodyContent wrapper inside the panel
drawer-closeThe built-in close button (when showCloseButton)
drawer-headerThe Drawer.Header container
drawer-titleThe Drawer.Title element
drawer-descriptionThe Drawer.Description element
drawer-bodyThe Drawer.Body container
drawer-footerThe Drawer.Footer container

Accessibility

  • Uses role="dialog" with aria-modal="true".
  • Focus is trapped within the drawer and restored on close.
  • Supports dismissal with Escape key and swipe gestures.
  • Default aria-label is "Drawer". Pass aria-label or aria-labelledby on Drawer.Content to give the dialog a meaningful name.
  • Close button label defaults to "Close". Override with the closeLabel prop for localisation or context-specific copy (e.g. "Close settings").
  • Respects motion preferences: drawer slide motion is enabled only when prefers-reduced-motion: no-preference.