# Drawer

> A modal bottom sheet with a grab handle, draggable shut with a downward swipe — for filters, quick actions, or any touch-first task.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Overlays
- Tags: overlay, drawer, bottom sheet, modal, swipe, mobile
- Docs: https://fancy-ui.rama.app/docs/components/drawer
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/drawer

## Import

```svelte
<script lang="ts">
  import { Drawer } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { Drawer } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `open` | `boolean` | `false` | Whether the drawer is open. Bindable |
| `onOpenChange` | `(open: boolean) => void` | — | Called with the new value whenever the drawer opens or closes |
| `title` | `string` | — | Heading rendered in the header and wired to aria-labelledby |
| `description` | `string` | — | Supporting text under the title, wired to aria-describedby |
| `dismissible` | `boolean` | `true` | Whether Escape, the scrim, the close button and the swipe gesture can close the drawer |
| `swipeToClose` | `boolean` | `true` | Whether dragging the handle down past the threshold closes the drawer |
| `class` | `string` | — | Additional CSS classes merged onto the panel |
| `ref` | `HTMLDivElement \| null` | `null` | Bindable element reference to the panel |
| `sound` | `boolean` | `false` | Plays close when the drawer is dismissed, including a committed swipe, once the user has enabled sound |

## Snippets

| Snippet | Description |
| --- | --- |
| `children` | Panel body content |
| `footer` | Content pinned below the body, e.g. actions |

## Examples

### Basic Usage

```svelte
<script lang="ts">
	import { Drawer } from "fancy-ui-svelte";
	import { Button } from "fancy-ui-svelte";

	let open = $state(false);
	let sortBy = $state("recent");
</script>

<Button onclick={() => (open = true)}>Open filters</Button>

<Drawer sound bind:open title="Filters" description="Drag down to close.">
	<div class="flex flex-col gap-2">
		<label class="text-muted-foreground flex items-center gap-2 text-[13px]">
			<input type="radio" name="sort" value="recent" bind:group={sortBy} />
			Most recent
		</label>
		<label class="text-muted-foreground flex items-center gap-2 text-[13px]">
			<input type="radio" name="sort" value="popular" bind:group={sortBy} />
			Most popular
		</label>
	</div>
</Drawer>
```

### With Form

House form fields with a pinned footer.

```svelte
<script lang="ts">
	import { Drawer } from "fancy-ui-svelte";
	import { Button } from "fancy-ui-svelte";
	import { FormField } from "fancy-ui-svelte";
	import { Input } from "fancy-ui-svelte";
	import { Textarea } from "fancy-ui-svelte";

	let open = $state(false);
	let subject = $state("");
	let message = $state("");

	function submit() {
		open = false;
	}
</script>

<Button onclick={() => (open = true)}>Send feedback</Button>

<Drawer sound bind:open title="Send feedback" {footer}>
	<div class="flex flex-col gap-4">
		<FormField label="Subject">
			<Input bind:value={subject} placeholder="What's this about?" />
		</FormField>
		<FormField label="Message">
			<Textarea bind:value={message} placeholder="Tell us more..." />
		</FormField>
	</div>
</Drawer>

{#snippet footer()}
	<Button variant="outline" onclick={() => (open = false)}>Cancel</Button>
	<Button onclick={submit}>Submit</Button>
{/snippet}
```

### No Swipe

Disable the drag-to-close gesture.

```svelte
<script lang="ts">
	import { Drawer } from "fancy-ui-svelte";
	import { Button } from "fancy-ui-svelte";

	let open = $state(false);
</script>

<Button onclick={() => (open = true)}>Open drawer</Button>

<Drawer
	sound
	bind:open
	swipeToClose={false}
	title="Filters"
	description="Swipe is off here — close with Escape, the scrim, or the close button."
>
	<p class="text-muted-foreground text-[13px]">Body content goes here.</p>
</Drawer>
```
