Sheet
A panel that docks to an edge of the window, on the raised surface.
A panel that slides in from an edge of the window for a filter set, a settings form, or a detail that should not take the reader off the page. It sits on the same Radix dialog as Dialog, so a scrim dims the page, focus stays inside, and Escape closes it. Dialog is centered and Sheet is docked. The mobile Sidebar is a Sheet.
Usage
import { Button } from '@/components/ui/button';
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@/components/ui/sheet';
<Sheet>
<SheetTrigger asChild>
<Button>Open</Button>
</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Title</SheetTitle>
<SheetDescription>Supporting copy.</SheetDescription>
</SheetHeader>
<SheetFooter>
<SheetClose asChild>
<Button variant="outline">Cancel</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>SheetHeader and SheetFooter are layout slots with 16px of padding, and the footer is
pushed to the bottom of the panel with mt-auto, so a short sheet still ends with its
actions at the edge. The header keeps its text clear of the close button, so a long title
wraps before it.
Pick an edge
side sets where the panel docks: right by default, or left, top, or bottom. A
left or right sheet fills the height and is three quarters of the window wide, up to
384px from the sm breakpoint. A top or bottom sheet fills the width and is as tall as
its content, with no maximum, so keep what goes in one short. The panel slides in from its
edge, and a border on the side facing the page marks where it ends.
Use right for detail and settings, and left for navigation, which is where the
Sidebar puts it.
Controlling it
Pass open and onOpenChange to open a sheet from somewhere else, such as a menu item, a
keyboard shortcut, or a button that lives far from the sheet, and leave out SheetTrigger.
Focus returns to a SheetTrigger when the sheet closes. A sheet without one has nowhere to
send it, so focus is not moved back, and onCloseAutoFocus on SheetContent is where you
put it.
Modal or not
A Sheet is modal by default, which is what gives it the scrim, the focus trap, the inert page
behind it, and the scroll lock. modal={false} on Sheet turns all four off, and the sheet
then docks beside a page that stays usable. Tapping the page behind a non-modal sheet closes
it.
Props
Sheet, SheetTrigger, SheetClose, SheetTitle, and SheetDescription are the Radix
dialog parts, with open, defaultOpen, onOpenChange, and modal as on Dialog.
SheetContent takes the Radix content props, plus these.
| Prop | Type | Default | What it does |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "right" | The edge the panel docks to, and the edge it slides in from. |
showCloseButton | boolean | true | Shows the X in the top right corner. Turn it off when the sheet has its own close control. |
SheetOverlay and SheetPortal are exported for composing your own content, and
SheetContent already includes both.
Accessibility
- The panel has
role="dialog".SheetTitlenames it andSheetDescriptiondescribes it, and each is wired up only when it is rendered, so give a sheet a title even when it is hidden withsr-only, as the Sidebar does. - Focus moves into the panel on open, to the first focusable element in it. Tab and Shift+Tab stay inside, and Escape or a click on the scrim closes it. On close, focus goes back to the trigger.
- With
modalon, the rest of the page is hidden from assistive tech and cannot scroll. - The close button is a native button named "Close", and its focus ring shows on
:focus-visibleonly. It is 36px square, and 44px on a coarse pointer such as a touch screen, at any width. - Under reduced motion the panel and the scrim appear and disappear without animating.
- A sheet does not scroll its own content. Put a scrolling region inside it when the content
can be long, since
topandbottomsheets have no maximum height and can grow past the window. - The edge border is a real border, so the panel stays outlined in forced colors. The close button keeps a transparent outline on focus that the system paints, so focus stays visible in Windows high contrast.
When to use something else
- Dialog for a focused decision or a short form that should sit in the middle of the window.
- Alert dialog or Confirm when the user has to answer before anything else, with no close control and no click-outside dismiss.
- Drawer on phones, where a bottom sheet you can drag between heights is easier to reach than a docked panel. Sheet is the one to use on a wide screen.
- Popover when the content belongs to a control and the page behind it should stay usable.
Install
shadcn add @gesso/sheet