---
id: drawer
title: Drawer
description: A panel that slides in from the edge of the screen, typically used for navigation or forms.
status: Preview
---

<ComponentPreview id="Drawer" />

## Anatomy

<Anatomy id="drawer" />

```tsx
<Drawer.Root>
  <Drawer.Trigger />
  <Drawer.Backdrop />
  <Drawer.Positioner>
    <Drawer.Content>
      <Drawer.Grabber>
        <Drawer.GrabberIndicator />
      </Drawer.Grabber>
      <Drawer.Title />
      <Drawer.Description />
      <Drawer.CloseTrigger />
    </Drawer.Content>
  </Drawer.Positioner>
</Drawer.Root>
```

## Examples

<Example id="basic" />

### Swipe Direction

Use the `swipeDirection` prop to control which edge the drawer slides in from.

<Example id="swipe-direction" />

### Snap Points

Use the `snapPoints` prop to define intermediate positions the drawer can snap to.

<Example id="snap-points" />

### Modal

Set `modal` to `false` to allow interaction with the rest of the page while the drawer is open.

<Example id="modal" />

### Controlled

Use the `open` and `onOpenChange` props to control the drawer state.

<Example id="controlled" />

### Scrollable

<Example id="scrollable" />

### No Drag Area

Apply the `data-no-drag` attribute to any element inside the drawer to prevent dragging from starting on it.

<Example id="no-drag-area" />

### Non Draggable

Set `draggable` to `false` to disable drag-to-dismiss entirely.

<Example id="non-draggable" />

### Indent Background

Use `Drawer.IndentBackground` to create a visual indent effect on the page behind the drawer.

<Example id="indent-background" />

### Multiple Triggers

Use the `value` prop on `Drawer.Trigger` to share a single drawer across multiple trigger elements. The
`onTriggerValueChange` callback fires when a different trigger is activated.

<Example id="multiple-triggers" />

### Using the Root Provider

Use the `useDrawer` hook and `Drawer.RootProvider` to control the drawer from outside the component tree.

<Example id="root-provider" />

## Guides

### Styling by Swipe Direction

The `Drawer.Content` elements expose a `data-swipe-direction` attribute (`up` | `down` | `left` | `right`) that reflects
the resolved physical direction the drawer slides in from.

Target it to apply direction-aware styles — for example, rounded corners on the side facing the viewport:

```css
[data-scope='drawer'][data-part='content'] {
  /* Top drawer */
  &[data-swipe-direction='up'] {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    border-bottom-left-radius: 16px;
    border-bottom-right-radius: 16px;
  }

  /* Bottom drawer */
  &[data-swipe-direction='down'] {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
  }

  /* Left drawer */
  &[data-swipe-direction='left'] {
    border-top-left-radius: 0;
    border-bottom-right-radius: 16px;
    border-top-left-radius: 16px;
    border-top-right-radius: 0;
  }

  /* Right drawer */
  &[data-swipe-direction='right'] {
    border-top-right-radius: 0;
    border-bottom-left-radius: 16px;
    border-top-left-radius: 0;
    border-top-right-radius: 16px;
  }
}
```

### Preventing Overdrag Gaps

When a user drags the drawer past its open position, a small gap can appear between the drawer content and the viewport
edge. To prevent this, extend the drawer's background beyond its visible bounds using a CSS `::after` pseudo-element:

```css
[data-scope='drawer'][data-part='content'] {
  --bleed: 3rem;
  position: relative;

  /* Bleed effect */
  &::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: 100%;
    height: var(--bleed);
    background-color: inherit;
    pointer-events: none;
  }
}
```

For side drawers, adjust the pseudo-element to extend horizontally:

```css
[data-scope='drawer'][data-part='content'] {
  /* Right drawer */
  &[data-swipe-direction='right']::after {
    inset-inline: auto;
    inset-block: 0;
    top: 0;
    left: 100%;
    width: var(--bleed);
    height: auto;
  }

  /* Left drawer */
  &[data-swipe-direction='left']::after {
    inset-inline: auto;
    inset-block: 0;
    top: 0;
    right: 100%;
    width: var(--bleed);
    height: auto;
  }
}
```

The `::after` element inherits the drawer's background color and sits just outside the content bounds. During overdrag,
the dampened movement reveals this extension instead of an empty gap.

## API Reference

### Props

<ComponentTypes id="drawer" />

### Context

<ContextType id="drawer" />

## Accessibility

Complies with the [Dialog WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).

<KeyBindingsTable id="dialog" />
