---
title: Drawer
description: "A swipeable panel that slides in from the edge of the screen."
---

```tsx
import { Button } from '@/components/ui/button';
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from '@/components/ui/drawer';

export default function DrawerDemo() {
  return (
    <Drawer showSwipeHandle>
      <DrawerTrigger render={<Button variant="outline" />}>
        Open drawer
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>Move goal</DrawerTitle>
          <DrawerDescription>Set your daily activity goal.</DrawerDescription>
        </DrawerHeader>
        <DrawerFooter>
          <DrawerClose render={<Button />}>Submit</DrawerClose>
          <DrawerClose render={<Button variant="outline" />}>Cancel</DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  );
}
```

## Install

```bash
npx shadcn@latest add @madeui/drawer
```

## Usage

```tsx
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from '@/components/ui/drawer';
```

## Composition

```tsx
<Drawer>
  <DrawerTrigger />
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle />
      <DrawerDescription />
    </DrawerHeader>
    <DrawerFooter>
      <DrawerClose />
    </DrawerFooter>
  </DrawerContent>
</Drawer>
```

## Directions

`swipeDirection` sets which edge the drawer rests on and swipes back toward.

```tsx
import * as stylex from '@stylexjs/stylex';

import { Button } from '@/components/ui/button';
import {
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
  type DrawerSwipeDirection,
} from '@/components/ui/drawer';
import { space } from '@/lib/constants.stylex';

const directions: DrawerSwipeDirection[] = ['up', 'right', 'down', 'left'];

export default function DrawerDirections() {
  return (
    <div {...stylex.props(styles.row)}>
      {directions.map((direction) => (
        <Drawer key={direction} swipeDirection={direction}>
          <DrawerTrigger render={<Button variant="outline" />}>
            {direction}
          </DrawerTrigger>
          <DrawerContent>
            <DrawerHeader>
              <DrawerTitle>Drawer from {direction}</DrawerTitle>
              <DrawerDescription>
                Rests on and swipes back toward the {direction} edge.
              </DrawerDescription>
            </DrawerHeader>
          </DrawerContent>
        </Drawer>
      ))}
    </div>
  );
}

const styles = stylex.create({
  row: {
    display: 'flex',
    flexWrap: 'wrap',
    gap: space.s2,
  },
});
```

## API reference

Built on [Base UI Drawer](https://base-ui.com/react/components/drawer). Swipe-to-dismiss and snap points come from the primitive — Base UI drives the swipe offsets through CSS variables that the styles consume. All props are forwarded to the Base UI `Root` (`open`, `snapPoints`, `modal`, `swipeDirection`, …); see the [Base UI Drawer API reference](https://base-ui.com/react/components/drawer#api-reference).

Unlike `Sheet` (a fixed side panel on the Dialog primitive), Drawer is gesture-driven — prefer it on touch-first surfaces.

### Drawer

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `swipeDirection` | `'down' \| 'up' \| 'left' \| 'right'` | `'down'` | Edge the drawer rests on and dismisses toward. |
| `showSwipeHandle` | `boolean` | `false` | Renders a grab handle on the swipe edge. |

Nested drawer stacking (scale/peek of the drawer behind) is not styled yet. Every part accepts a `style` prop (`StyleXStyles`, merged last).
