---
title: Drawer
description: "Astro edge panels with data-slot dragging and dismissal."
seo:
    title: "Drawer for Astro — examples and usage"
---

This Astro component uses [data-slot](https://data-slot.com/components/drawer/)
for behavior and [Coss UI](https://coss.com/ui/docs/components/drawer) for its style.
It uses the current theme colors, rounded edges, a blurred backdrop, and a muted footer.

```astro
---
import {
  Drawer,
  DrawerTrigger,
  DrawerPopup,
  DrawerHeader,
  DrawerTitle,
  DrawerDescription,
  DrawerPanel,
  DrawerFooter,
  DrawerClose,
} from "@/components/ui/drawer"
---

<Drawer>
  <DrawerTrigger variant="outline">Open drawer</DrawerTrigger>
  <DrawerPopup showBar showCloseButton>
    <DrawerHeader>
      <DrawerTitle>Your workspace</DrawerTitle>
      <DrawerDescription>
        Keep the tools you need within reach.
      </DrawerDescription>
    </DrawerHeader>
    <DrawerPanel>
      <p>
        Swipe down to close this panel. You can also press Escape or select
        Done.
      </p>
    </DrawerPanel>
    <DrawerFooter>
      <DrawerClose>Done</DrawerClose>
    </DrawerFooter>
  </DrawerPopup>
</Drawer>
```

## Installation

```sh
bunx --bun shadcn@latest add @gnosticai/drawer
```

## Usage

```astro
---
import {
  Drawer, DrawerTrigger, DrawerPopup, DrawerHeader, DrawerTitle,
  DrawerDescription, DrawerPanel, DrawerFooter, DrawerClose,
  DrawerMenu, DrawerMenuItem,
} from "@/components/ui/drawer"
---

<Drawer position="right">
  <DrawerTrigger>Open menu</DrawerTrigger>
  <DrawerPopup variant="inset" showCloseButton>
    <DrawerHeader>
      <DrawerTitle>Menu</DrawerTitle>
    </DrawerHeader>
    <DrawerPanel>
      <DrawerMenu aria-label="Site navigation">
        <DrawerMenuItem as="a" href="/about" closeOnSelect>About</DrawerMenuItem>
        <DrawerMenuItem as="a" href="/contact" closeOnSelect>Contact</DrawerMenuItem>
      </DrawerMenu>
    </DrawerPanel>
  </DrawerPopup>
</Drawer>
```

Always include `DrawerTitle`. Use `class="sr-only"` to hide the title visually.
Use Astro's `as` prop for link controls. `DrawerMenuItem` keeps the drawer open
unless `closeOnSelect` is set. Links keep their normal navigation behavior.

## Positions and styles

The root sets both the screen edge and the swipe direction. `DrawerPopup`
includes the portal, backdrop, and viewport.

```astro
---
import {
  Drawer, DrawerTrigger, DrawerPopup, DrawerHeader, DrawerTitle, DrawerDescription,
} from "@/components/ui/drawer"
---

<div class="flex flex-wrap gap-3">
  <Drawer position="left">
    <DrawerTrigger variant="outline">Left inset</DrawerTrigger>
    <DrawerPopup variant="inset" showCloseButton>
      <DrawerHeader>
        <DrawerTitle>Left drawer</DrawerTitle>
        <DrawerDescription>The inset style adds space on larger screens.</DrawerDescription>
      </DrawerHeader>
    </DrawerPopup>
  </Drawer>
  <Drawer position="right">
    <DrawerTrigger variant="outline">Right</DrawerTrigger>
    <DrawerPopup showCloseButton>
      <DrawerHeader><DrawerTitle>Right drawer</DrawerTitle></DrawerHeader>
    </DrawerPopup>
  </Drawer>
  <Drawer position="top">
    <DrawerTrigger variant="outline">Top straight</DrawerTrigger>
    <DrawerPopup variant="straight" showCloseButton>
      <DrawerHeader><DrawerTitle>Top drawer</DrawerTitle></DrawerHeader>
    </DrawerPopup>
  </Drawer>
</div>
```

## Scrollable content

The panel scrolls while the title and footer stay in place. Native scrolling
keeps long menus usable on small screens.

```astro
---
import {
  Drawer, DrawerTrigger, DrawerPopup, DrawerHeader, DrawerTitle,
  DrawerPanel, DrawerFooter, DrawerClose,
} from "@/components/ui/drawer"
---

<Drawer>
  <DrawerTrigger variant="outline">Long content</DrawerTrigger>
  <DrawerPopup showBar>
    <DrawerHeader><DrawerTitle>Workspace notes</DrawerTitle></DrawerHeader>
    <DrawerPanel>
      <ol class="flex flex-col gap-4">
        {Array.from({ length: 30 }, (_, i) => <li>Note {i + 1}: Keep each task clear and easy to find.</li>)}
      </ol>
    </DrawerPanel>
    <DrawerFooter><DrawerClose>Done</DrawerClose></DrawerFooter>
  </DrawerPopup>
</Drawer>
```

## Nested drawers

Place a complete drawer inside the parent panel. Escape and swipe dismiss the
front drawer first. Focus returns to its trigger.

```astro
---
import {
  Drawer,
  DrawerTrigger,
  DrawerPopup,
  DrawerHeader,
  DrawerTitle,
  DrawerPanel,
  DrawerFooter,
  DrawerClose,
} from "@/components/ui/drawer"
---

<Drawer>
  <DrawerTrigger variant="outline">Nested drawers</DrawerTrigger>
  <DrawerPopup showBar>
    <DrawerHeader>
      <DrawerTitle>Workspace</DrawerTitle>
    </DrawerHeader>
    <DrawerPanel>
      <Drawer>
        <DrawerTrigger variant="outline">Open details</DrawerTrigger>
        <DrawerPopup showBar>
          <DrawerHeader>
            <DrawerTitle>Details</DrawerTitle>
          </DrawerHeader>
          <DrawerPanel>Swipe down to return to the workspace.</DrawerPanel>
          <DrawerFooter>
            <DrawerClose>Back</DrawerClose>
          </DrawerFooter>
        </DrawerPopup>
      </Drawer>
    </DrawerPanel>
    <DrawerFooter>
      <DrawerClose>Done</DrawerClose>
    </DrawerFooter>
  </DrawerPopup>
</Drawer>
```

## Props

<table>
	<thead>
		<tr>
			<th>Component</th>
			<th>Prop</th>
			<th>Default</th>
			<th>Use</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>Drawer</td>
			<td>
				<code>position</code>
			</td>
			<td>
				<code>"bottom"</code>
			</td>
			<td>
				<code>"bottom"</code>, <code>"top"</code>, <code>"left"</code>, or{" "}
				<code>"right"</code>
			</td>
		</tr>
		<tr>
			<td>Drawer</td>
			<td>
				<code>defaultOpen</code>
			</td>
			<td>
				<code>false</code>
			</td>
			<td>Open when the component starts</td>
		</tr>
		<tr>
			<td>Drawer</td>
			<td>
				<code>modal</code>
			</td>
			<td>
				<code>true</code>
			</td>
			<td>
				<code>true</code>, <code>false</code>, or <code>"trap-focus"</code>
			</td>
		</tr>
		<tr>
			<td>Drawer</td>
			<td>
				<code>closeOnEscape</code>
			</td>
			<td>
				<code>true</code>
			</td>
			<td>Allow Escape to close the drawer</td>
		</tr>
		<tr>
			<td>Drawer</td>
			<td>
				<code>disablePointerDismissal</code>
			</td>
			<td>
				<code>false</code>
			</td>
			<td>Prevent outside clicks from closing it</td>
		</tr>
		<tr>
			<td>Drawer</td>
			<td>
				<code>closeOnMedia</code>
			</td>
			<td>—</td>
			<td>Close when this CSS media query matches</td>
		</tr>
		<tr>
			<td>DrawerPopup</td>
			<td>
				<code>variant</code>
			</td>
			<td>
				<code>"default"</code>
			</td>
			<td>
				<code>"default"</code>, <code>"straight"</code>, or <code>"inset"</code>
			</td>
		</tr>
		<tr>
			<td>DrawerPopup</td>
			<td>
				<code>showBar</code> / <code>showCloseButton</code>
			</td>
			<td>
				<code>false</code>
			</td>
			<td>Show the swipe bar or close button</td>
		</tr>
		<tr>
			<td>DrawerPopup</td>
			<td>
				<code>keepMounted</code>
			</td>
			<td>
				<code>false</code>
			</td>
			<td>Keep the closed portal at its destination</td>
		</tr>
		<tr>
			<td>DrawerPopup</td>
			<td>
				<code>container</code>
			</td>
			<td>
				<code>"body"</code>
			</td>
			<td>CSS selector for the portal destination</td>
		</tr>
		<tr>
			<td>DrawerPopup</td>
			<td>
				<code>initialFocus</code> / <code>finalFocus</code>
			</td>
			<td>runtime default</td>
			<td>Boolean or CSS selector</td>
		</tr>
		<tr>
			<td>DrawerPanel</td>
			<td>
				<code>scrollable</code>
			</td>
			<td>
				<code>true</code>
			</td>
			<td>Use native scrolling for long content</td>
		</tr>
		<tr>
			<td>DrawerFooter</td>
			<td>
				<code>variant</code>
			</td>
			<td>
				<code>"default"</code>
			</td>
			<td>
				Use <code>"bare"</code> to remove its border and background
			</td>
		</tr>
		<tr>
			<td>DrawerMenuItem</td>
			<td>
				<code>closeOnSelect</code>
			</td>
			<td>
				<code>false</code>
			</td>
			<td>Close when the item is selected</td>
		</tr>
		<tr>
			<td>DrawerMenuItem</td>
			<td>
				<code>variant</code>
			</td>
			<td>
				<code>"default"</code>
			</td>
			<td>
				Use <code>"destructive"</code> for a destructive action
			</td>
		</tr>
	</tbody>
</table>

These wrappers provide full-size drawers. Coss React props such as `render`,
`onOpenChange`, and multi-point `snapPoints` are not Astro props. For application
state, use data-slot's `drawer:open`, `drawer:close`, and `drawer:change` DOM events.

For a complete navigation block, see [Mobile Menu](/blocks/mobile-menu).

## When to use Drawer

Use Drawer for a short task or detail view that enters from a screen edge. Keep a title and explicit close control. Choose the direction that fits the page; a bottom drawer can work well for short mobile actions.

## Keyboard and behavior

The current controller handles dragging, Escape, and modal focus. Keep a close button available so dragging is never the only way out. Multi-point Coss snap positions are not part of this Astro API.

## Theme and layout

The drawer uses shared dialog colors and direction-specific motion. Test long content while dragging and scrolling on touch screens. A larger drawer needs a constrained body so controls remain reachable.

## Related choices

Use [Sheet](/components/sheet) for an edge panel without drawer gestures or [Dialog](/components/dialog) for a centered task.
