# Sheet

An accessible React sheet for Next.js: a side panel that slides in from any edge of the screen, for forms, filters and navigation, built on Radix Dialog.

Source: https://ui.fewtone.com/components/sheet

## Installation

```bash
npx shadcn@latest add https://ui.fewtone.com/r/sheet.json
```

## Usage

```tsx
import { Button } from "@/components/ui/button"
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"

export function Filters() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="outline">Filters</Button>
      </SheetTrigger>
      <SheetContent side="right">
        <SheetHeader>
          <SheetTitle>Filters</SheetTitle>
          <SheetDescription>Narrow the results.</SheetDescription>
        </SheetHeader>
      </SheetContent>
    </Sheet>
  )
}
```

## API reference

### Sheet

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `open` | `boolean` | – | Whether it's open, when you control it. |
| `defaultOpen` | `boolean` | `false` | Whether it starts open. |
| `onOpenChange` | `(open: boolean) => void` | – | Called when it opens or closes: the trigger, a close button, Escape or the backdrop. |
| `modal` | `boolean` | `true` | Modal blocks the page behind, hides it from screen readers and keeps focus inside. Set false to let people use the page while it's open (there's no backdrop then). |

### SheetTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Use your own element, such as a Button, as the trigger. |

### SheetContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"right"` | The edge it slides in from. Right and left panels are three quarters of the screen wide, up to 24rem; top and bottom ones are as tall as their content. |
| `showCloseButton` | `boolean` | `true` | Shows a close button in the top corner, named Close. |
| `onOpenAutoFocus` | `(event: Event) => void` | – | Runs as focus moves in (to the first focusable element). Call event.preventDefault() to focus something else yourself. |
| `onCloseAutoFocus` | `(event: Event) => void` | – | Runs as focus goes back to the trigger. Call event.preventDefault() to send it elsewhere. |
| `onEscapeKeyDown` | `(event: KeyboardEvent) => void` | – | Runs when Escape is pressed. Call event.preventDefault() to keep it open. |

### SheetHeader

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### SheetFooter

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### SheetTitle

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### SheetDescription

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### SheetClose

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Use your own element as the close button. |

**When to use it:** Use Sheet for a panel beside the page: a form, filters, settings or navigation on small screens. Use Dialog for a short task in the middle of the screen, and Alert Dialog to confirm a destructive action.
**Built on:** Radix Dialog.
**Accessibility pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
**npm packages (installed by the CLI):** class-variance-authority@^0.7.1, lucide-react@^1.52.0, motion@^14.0.0, radix-ui@^1.7.0.
**Installs these FewTone UI components with it:** `button`.

## Examples

### Sides

A sheet slides in from any edge and slides back out quickly. The backdrop fades, and the page behind waits until it's closed.

```tsx
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Sheet,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet";
import { PanelBottomIcon, PanelLeftIcon, PanelRightIcon, PanelTopIcon } from "lucide-react";
import { useId } from "react";

const sides = [
  { side: "top", label: "Top", Icon: PanelTopIcon },
  { side: "right", label: "Right", Icon: PanelRightIcon },
  { side: "bottom", label: "Bottom", Icon: PanelBottomIcon },
  { side: "left", label: "Left", Icon: PanelLeftIcon },
] as const;

/** The same form in a sheet from each edge, each button named underneath */
export default function SheetSides() {
  const id = useId();
  return (
    <ul className="flex flex-wrap items-end justify-center gap-x-8 gap-y-6">
      {sides.map(({ side, label, Icon }) => (
        <li key={side} className="flex flex-col items-center gap-2">
          <Sheet>
            <SheetTrigger asChild>
              <Button variant="outline" size="icon" aria-label={`Open a sheet from the ${side}`}>
                <Icon />
              </Button>
            </SheetTrigger>
            <SheetContent side={side}>
              <SheetHeader>
                <SheetTitle>Edit profile</SheetTitle>
                <SheetDescription>Change how others see you. Save when you're done.</SheetDescription>
              </SheetHeader>
              {/* Capped, so the fields stay a comfortable width in a sheet across the top or bottom */}
              <div className="grid gap-4 sm:max-w-sm">
                <div className="grid gap-2">
                  <label htmlFor={`${id}-${side}-name`} className="text-sm font-medium">
                    Name
                  </label>
                  <Input id={`${id}-${side}-name`} defaultValue="Maya Chen" autoComplete="name" />
                </div>
                <div className="grid gap-2">
                  <label htmlFor={`${id}-${side}-username`} className="text-sm font-medium">
                    Username
                  </label>
                  <Input id={`${id}-${side}-username`} defaultValue="maya" autoComplete="username" />
                </div>
              </div>
              <SheetFooter>
                <SheetClose asChild>
                  <Button>Save changes</Button>
                </SheetClose>
              </SheetFooter>
            </SheetContent>
          </Sheet>
          <span aria-hidden className="text-xs text-muted-foreground">
            {label}
          </span>
        </li>
      ))}
    </ul>
  );
}
```

## Related

- [Dialog](https://ui.fewtone.com/components/dialog.md): An accessible React dialog for Next.js and Tailwind CSS: a modal window that grows out of its trigger, keeps focus inside and returns it, built on Radix Dialog.
- [Alert Dialog](https://ui.fewtone.com/components/alert-dialog.md): An accessible React alert dialog for Next.js that asks people to confirm destructive actions, with focus starting on Cancel, built on Radix Alert Dialog.
