Sheet
StableA panel that slides in from the edge of the screen for longer forms, details and filters, while keeping the page underneath in context.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/sheet.jsonUsage
import {
Sheet,
SheetBody,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet"<Sheet>
<SheetTrigger render={<Button variant="outline" />}>Edit issue</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit issue</SheetTitle>
<SheetDescription>DAT-248 · Opened by Ada Lovelace</SheetDescription>
</SheetHeader>
<SheetBody>{/* scrollable content */}</SheetBody>
<SheetFooter>
<SheetClose render={<Button variant="outline" />}>Cancel</SheetClose>
<Button>Save issue</Button>
</SheetFooter>
</SheetContent>
</Sheet>A sheet is a Dialog that lives on an edge. It shares the same behavior — focus trap, scroll lock, Esc to close — and adds a three-part layout: a fixed SheetHeader, a scrolling SheetBody and a SheetFooter pinned to the bottom.
Examples
Sides
side chooses the edge: right (the default) for details and editing, left for navigation, top and bottom for short, full-width content. Sheets on the left or right are 26rem wide, never closer than 3rem to the opposite edge; sheets on the top or bottom take at most 85% of the viewport height.
Floating
variant="floating" insets the sheet from the viewport by 8px and rounds all its corners, so it reads as a surface above the page rather than part of the window frame. It suits lightweight panels such as notifications.
Filters
Filters are the canonical sheet: many controls, applied to a list that stays visible behind the scrim. Put the result count in the primary action so people know what they'll get before they commit.
Navigation
On small screens, the app navigation moves into a left sheet opened from a menu button. Mark the current page with aria-current="page".
Width
The width is a regular utility, so override it with className — for example className="w-[min(40rem,calc(100%-3rem))]" for a wide detail view.
Guidelines
When to use
- To edit or inspect an item from a list without losing your place in it.
- For forms that are too long for a dialog but don't deserve their own page.
- For secondary navigation and filters on small screens.
When not to use
- For a quick decision or a short form — use a Dialog.
- For mobile bottom panels with swipe gestures and snap points — use a Drawer.
- For permanent side navigation on large screens — use a Sidebar.
Structure
Keep the header and footer short so the body gets the space. The title names the object, the description adds one line of context (an ID, an owner, a count), and the footer holds at most two actions plus an optional Reset on the far side.
Don’t stack
Opening a dialog on top of a sheet is acceptable for confirmations. Opening a sheet on top of a sheet is not — replace the content, or move to a page.
Accessibility
A sheet is a modal dialog with role="dialog", labeled by SheetTitle and described by SheetDescription.
| Key | Behavior |
|---|---|
EnterSpace | On the trigger: opens the sheet and moves focus into it. |
Tab | Moves through the sheet's controls. Focus is trapped until it closes. |
ShiftTab | Moves focus backwards, wrapping at the start. |
Esc | Closes the sheet and returns focus to the trigger. |
- Always include a title. Use
className="sr-only"onSheetTitlewhen the design shows something else, such as a logo. - The close button (
showCloseButton, on by default) is how touch screen reader users leave. Keep it, or put aSheetClosein the footer. - Reading order. The header, body and footer follow DOM order, so the footer's actions come after the content for screen readers and keyboard users — the same order people see.
- Motion. Sheets slide in over 320ms with the
entereasing and leave in 160ms. With reduced motion, they appear in place.
API reference
Sheet
The root. Doesn't render an element. Accepts every prop of Base UI Dialog.Root: open, defaultOpen, onOpenChange, modal, disablePointerDismissal, actionsRef.
SheetContent
Renders the portal, scrim and panel.
SheetHeader, SheetBody, SheetFooter
SheetHeader holds the title and description and leaves room for the close button. SheetBody grows to fill the panel and scrolls on its own. SheetFooter is pinned to the bottom with a hairline border; it stacks on small screens and right-aligns from sm up.
SheetTitle, SheetDescription
SheetTitle renders an <h2> and names the sheet. SheetDescription renders a <p> and describes it.
SheetTrigger, SheetClose
Open and close the sheet. Both render a <button>; use render to render a prfct Button.