Home

Sheet

A panel that slides in from an edge of the window over a dimmed page, with a header, a scrolling panel and a footer.

ui.sheetcomponents/ui/sheet.tsx

Use case

For the AI

Use it for work that needs more height than a dialog while keeping the page in sight: the filters of an orders list, a client's full details opened from a table row, a new invoice with many lines. It comes from the right by default (`side` also takes left, top and bottom), and `variant="inset"` floats it a little off the window's edges with rounded corners.

Use it when

  • Filters or view settings for the list behind it
  • Reading or editing one record opened from a table row
  • A form longer than a dialog comfortably holds
  • The tool's places on a narrow window (`side="left"`)

Use something else when

  • A short task of a few fields: Dialog
  • A panel on a phone that follows the finger and closes with a swipe: Drawer
  • The tool's main navigation on a wide window: Sidebar

Examples

Code

Import

import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"
import {
  Sheet,
  SheetClose,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetPanel,
  SheetPopup,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"

Usage

<Sheet>
  <SheetTrigger render={<Button variant="secondary" />}>Filters</SheetTrigger>
  <SheetPopup side="right" variant="inset" className="sm:max-w-sm">
    <SheetHeader>
      <SheetTitle>Filters</SheetTitle>
      <SheetDescription>Narrow the list to what you need now.</SheetDescription>
    </SheetHeader>
    <SheetPanel className="grid gap-1">
      {["Unpaid only", "Assigned to me", "Due this week"].map((f) => (
        <Label key={f} className="flex h-11 items-center justify-between rounded-[12px] px-3 font-normal hover:bg-surface">
          {f}
          <Switch />
        </Label>
      ))}
    </SheetPanel>
    <SheetFooter>
      <SheetClose render={<Button variant="ghost" />}>Reset</SheetClose>
      <SheetClose render={<Button />}>Show 24 Results</SheetClose>
    </SheetFooter>
  </SheetPopup>
</Sheet>

Rules

  • Long content goes in `SheetPanel`, which scrolls between the header and footer and fades at its edges.
  • A `<form>` placed directly inside `SheetPopup` wraps the header, panel and footer and is laid out as contents, so the footer stays at the sheet's foot.
  • The footer's primary is last and says what it does, with a count when it has one ("Show 24 Results"); the way back (Reset, Cancel) comes before it.
  • A left or right sheet is capped at `max-w-md` and leaves part of the page showing; narrow it with `sm:max-w-sm`, never widen it into a page.