For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. An agent skill is available at /.well-known/agent-skills/site-skill.md.
Home

Sheet

A modal panel that slides in from any edge of the screen — for navigation, settings, and focused tasks.

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";

const SIDES = ["top", "right", "bottom", "left"] as const;

export const SheetDemo = () => (
    <div className="flex flex-col gap-6">
      {/* Side variants */}
      <div className="flex flex-wrap gap-2">
        {SIDES.map((side) => (
          <Sheet key={side}>
            <SheetTrigger asChild><Button variant="outline" className="capitalize">{side}</Button></SheetTrigger>
            <SheetContent side={side}>
              <SheetHeader>
                <SheetTitle>Sheet — {side}</SheetTitle>
                <SheetDescription>Slides in from the {side}. Click outside or press Esc to close.</SheetDescription>
              </SheetHeader>
            </SheetContent>
          </Sheet>
        ))}
      </div>
      {/* With form */}
      <Sheet>
        <SheetTrigger asChild><Button variant="outline">Edit profile</Button></SheetTrigger>
        <SheetContent>
          <SheetHeader>
            <SheetTitle>Edit profile</SheetTitle>
            <SheetDescription>Make changes to your profile here. Click save when done.</SheetDescription>
          </SheetHeader>
          <div className="flex flex-col gap-4 px-4">
            <div className="flex flex-col gap-1.5">
              <Label htmlFor="sheet-name">Name</Label>
              <Input id="sheet-name" defaultValue="Nuno Santos" />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label htmlFor="sheet-username">Username</Label>
              <Input id="sheet-username" defaultValue="@nunosantos" />
            </div>
          </div>
          <SheetFooter>
            <SheetClose asChild><Button variant="outline">Cancel</Button></SheetClose>
            <SheetClose asChild><Button>Save changes</Button></SheetClose>
          </SheetFooter>
        </SheetContent>
      </Sheet>
    </div>
  );

Side

Use the side prop on SheetContent to control which edge the panel slides from. Defaults to "right".

<SheetContent side="left">...</SheetContent>
<SheetContent side="bottom">...</SheetContent>
<SheetContent side="top">...</SheetContent>

With form

Combine SheetHeader, SheetFooter, SheetClose, and form fields for an edit panel pattern.

<Sheet>
  <SheetTrigger asChild>
    <Button variant="outline">Edit profile</Button>
  </SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>Edit profile</SheetTitle>
      <SheetDescription>
        Make changes to your profile here. Click save when done.
      </SheetDescription>
    </SheetHeader>
    <div className="flex flex-col gap-4 px-4">
      <div className="flex flex-col gap-1.5">
        <Label htmlFor="name">Name</Label>
        <Input id="name" defaultValue="Nuno Santos" />
      </div>
    </div>
    <SheetFooter>
      <SheetClose asChild>
        <Button variant="outline">Cancel</Button>
      </SheetClose>
      <SheetClose asChild>
        <Button>Save changes</Button>
      </SheetClose>
    </SheetFooter>
  </SheetContent>
</Sheet>

Controlled

const [open, setOpen] = useState(false);
 
<Sheet open={open} onOpenChange={setOpen}>
  <SheetTrigger asChild>
    <Button>Open</Button>
  </SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>Controlled sheet</SheetTitle>
    </SheetHeader>
  </SheetContent>
</Sheet>

With sounds

Pass sounds to play open/close audio feedback using drawerOpen / drawerClose.

<Sheet sounds>
  ...
</Sheet>

Sheet vs Drawer

SheetDrawer
PrimitiveRadix Dialogvaul
Drag to dismissNoYes (bottom)
All 4 sidesYesYes
Keyboard focus trapYesYes
Use forForms, settings, navMobile-style bottom sheets

Props

Sheet

PropTypeDefaultDescription
openboolean—Controlled open state
defaultOpenbooleanfalseUncontrolled initial state
onOpenChange(open: boolean) => void—Callback when state changes
soundsbooleanfalsePlays drawerOpen / drawerClose audio

SheetContent

PropTypeDefaultDescription
side"top" | "right" | "bottom" | "left""right"Which edge the panel slides from

Usage

import { Button } from "@/components/ui/button";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet";
 
<Sheet>
  <SheetTrigger asChild>
    <Button variant="outline">Open sheet</Button>
  </SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>Title</SheetTitle>
      <SheetDescription>Description here.</SheetDescription>
    </SheetHeader>
  </SheetContent>
</Sheet>

Specs

# Mint — Sheet Specs
 
## Component
- name: sheet
- file: registry/mint/sheet.tsx
- installs to: components/ui/sheet.tsx
- dependencies: radix-ui, lucide-react
- registryDependencies: none
 
## What is it
A Radix Dialog primitive re-skinned as a slide-in side panel. Use it for
focused tasks that need dedicated screen space — settings panels, edit forms,
navigation drawers. Prefer Sheet over a Dialog when content is too long for a
centred modal. Do not use it for non-modal flows; reach for a Drawer for
mobile-style swipe-to-dismiss patterns.
 
## Visual identity
Flat white (light) / near-black (dark) panel surface with a soft, translucent
green border along the attached edge — a hint of Mint at the edge of an
otherwise minimal surface. Shadow-lg gives depth. Transitions are asymmetric:
500 ms ease-in on open, 300 ms ease-in-out on close, giving a confident entry
and a quick exit.
 
## Design tokens
--background: oklch(1 0 0) / oklch(0.145 0 0)     — panel surface (bg-background)
--foreground: oklch(0.145 0 0) / oklch(0.985 0 0)  — SheetTitle text (text-foreground)
--muted-foreground: oklch(0.52 0.06 155) / oklch(0.6 0.06 155) — SheetDescription text
--secondary: oklch(0.95 0.04 155) / oklch(0.22 0.04 155)    — close button hover bg (data-[state=open]:bg-secondary)
--ring: oklch(0.5 0.14 155) / oklch(0.62 0.15 155)        — close button focus ring
--border: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%)    — panel edge border (border-l, border-r, border-b, border-t)
 
## Sub-components
- Sheet            → Radix Dialog.Root; accepts sounds prop (drawerOpen / drawerClose)
- SheetTrigger     → Dialog.Trigger; use asChild to wrap any element
- SheetClose       → Dialog.Close; use asChild with a Button for styled dismiss
- SheetPortal      → Dialog.Portal; renders children outside the DOM tree
- SheetOverlay     → fixed inset-0 z-50 bg-black/50; fades in/out with panel
- SheetContent     → panel container; side prop controls which edge; includes built-in close button
- SheetHeader      → flex flex-col gap-1.5 p-4; wraps title and description
- SheetFooter      → mt-auto flex flex-col gap-2 p-4; anchored to bottom of panel
- SheetTitle       → Dialog.Title; font-semibold text-foreground; required for a11y
- SheetDescription → Dialog.Description; text-sm text-muted-foreground
 
## External dependencies
- lucide-react: XIcon for the built-in close button
 
## States
- data-[state=open]:    panel and overlay animate in; close button bg activates (bg-secondary)
- data-[state=closed]:  panel and overlay animate out
- focus (close button): 2px ring in --ring colour with 2px offset; outline-hidden
- hover (close button): opacity-100 (from opacity-70 default)
- disabled (close button): pointer-events-none
 
## Conventions
- SheetTitle is required — it is the accessible name for the dialog; never omit it
- SheetDescription is optional but recommended when the purpose is not self-evident
- Use SheetClose asChild with Button variant="outline" for a Cancel action in SheetFooter
- Place primary actions last in SheetFooter (visual left-to-right: Cancel → Save)
- side defaults to "right"; use "left" for navigation drawers, "bottom" for mobile-style panels
- sounds / haptic: GIN Design exclusive — pass sounds to Sheet to play drawerOpen / drawerClose audio on open and close
- Sub-components expose data-slot attributes for CSS targeting:
  sheet, sheet-trigger, sheet-close, sheet-portal, sheet-overlay,
  sheet-content, sheet-header, sheet-footer, sheet-title, sheet-description

Installation

GIN Design Plugin
$ npx shadcn add https://gin-design.vercel.app/sheet