Components

Sheet

A panel that slides in from any edge of the screen to hold supplementary content, forms, or navigation without leaving the current page.

Basic usage

Compose a SheetTrigger and SheetContent. The Radix root manages open state for you — no useState required. Only the header and footer are padded, so free-standing content needs its own px-4.

Sides

Set side on SheetContent to choose the edge the panel enters from. Left and right panels span the viewport height at w-3/4, capped at sm:max-w-sm; top and bottom span its width and size to their content.

Header and footer

SheetFooter pins itself to the bottom of the panel — ideal for a primary action paired with a SheetClose dismiss button.

Scrollable content

SheetContent is a flex column, so a middle region with flex-1 overflow-y-auto takes the scroll and leaves the header and the mt-auto footer in place.

Sheet or Drawer?

Sheet is a Radix Dialog: it slides in on a fixed track and closes on Escape or a click on the overlay. Use it for filters, detail panels, and desktop-first side panels — the Tier 3 shell's MobileMenu is a side="left" sheet. When the panel should be dragged — a grab handle, momentum, swipe-to-dismiss on touch — use Drawer, which is built on vaul instead.

Sheet Props

PropTypeDefaultDescription
openbooleanControlled open state. Pair with onOpenChange.
defaultOpenbooleanfalseOpen state on first render, for uncontrolled usage.
onOpenChange(open: boolean) => voidCalled whenever the sheet opens or closes.
modalbooleantrueWhen true, the rest of the page is inert and hidden from assistive technology while the panel is open.
childrenrequiredReact.ReactNodeSheet trigger and content.

SheetContent Props

PropTypeDefaultDescription
side'top' | 'right' | 'bottom' | 'left''right'Edge the panel slides in from. left/right span the full height at w-3/4 (capped at sm:max-w-sm); top/bottom span the full width at h-auto.
closeLabelstring'Đóng'Visually hidden label on the built-in close button. The package default is Vietnamese — pass an English string in an English UI.
classNamestringMerged onto the panel with cn(); the usual place to widen a side panel past sm:max-w-sm.
…Radix ContentDialogPrimitive.ContentPropsEverything else is forwarded to Radix Dialog.Content — onEscapeKeyDown, onInteractOutside, onOpenAutoFocus, forceMount.

Parts

Every part that renders an element accepts className; on the styled parts it is merged onto the defaults with cn(). Sheet and SheetPortal render no element of their own, so they take no className — passing one is a type error; style SheetContent instead.

PropTypeDefaultDescription
SheetDialogPrimitive.RootStateful container. Holds the open state and the trigger/content pair.
SheetTriggerDialogPrimitive.TriggerElement that toggles the sheet. Pass asChild to render your own Button.
SheetPortalDialogPrimitive.PortalPortal target. SheetContent renders one already — reach for it only when building a custom panel shell.
SheetOverlayDialogPrimitive.OverlayDimmed backdrop (bg-ink/60, dark:bg-ink/80, backdrop-blur). Also rendered for you by SheetContent.
SheetContentDialogPrimitive.ContentThe sliding panel: portal + overlay + a flex column with gap-4 and a built-in close button.
SheetHeaderdivTop region for title and description. Carries its own p-4 — the panel itself is unpadded.
SheetTitleDialogPrimitive.TitleAccessible name for the panel. Required for screen-reader announcements.
SheetDescriptionDialogPrimitive.DescriptionSupporting text linked to the panel via aria-describedby.
SheetFooterdivBottom region for actions: mt-auto pins it to the base of the panel, p-4 matches the header.
SheetCloseDialogPrimitive.CloseDismisses the sheet. Use asChild to wrap a custom Button.

Accessibility

  • Built on Radix Dialog: the panel is a modal role="dialog" with focus trapped inside while open and restored to the trigger on close.
  • Always include a SheetTitle — it provides the aria-labelledby name announced to screen readers; SheetDescription wires up aria-describedby.
  • Pressing Esc or clicking the dimmed overlay closes the sheet. The built-in close button has no visible text — its accessible name is the visually hidden closeLabel, which defaults to the Vietnamese "Đóng", so pass closeLabel="Close" in English interfaces.
  • Content outside the open panel is inert and hidden from assistive technology, keeping keyboard navigation scoped to the sheet.