Vesyl UI

Sheet

A panel that slides in from the edge of the screen, anchored to one side. Built on base-ui Dialog — it is a modal dialog styled as a side drawer, so it inherits focus trapping, scroll locking, the backdrop, and Esc-to-close for free.

Compose the same parts as a Dialog: Sheet (root, owns open state), SheetTrigger (opens it), SheetContent (the drawer surface, takes side and size), and the layout helpers SheetHeader, SheetTitle, SheetDescription, SheetFooter, and SheetClose.

Reach for a Sheet over a Dialog when the content is long, scrollable, or secondary to the page behind it — order detail, an activity log, or a filter panel that the user scans against the list still visible at the edge. Keep a centered Dialog for short, focused decisions (confirm, a small form).

Default

Sheet is uncontrolled — SheetTrigger toggles it. SheetContent defaults to side="right". Put the title and summary in a SheetHeader, the scrollable body in a flex-1 overflow-y-auto region, and the actions in a SheetFooter (which pins itself to the bottom via mt-auto).

Sides

side anchors the drawer to one edge: "right" (default), "left", "top", or "bottom". Left/right sheets fill the viewport height; top/bottom sheets fill its width and auto-size their height to the content.

Size

size sets the drawer width on sm+ screens — sm (default) through 4xl, plus full. It only applies to side="left" and side="right"; top and bottom sheets ignore it and size to their content. Widen the sheet for forms and multi-column detail, like this filter panel.

Controlled

Sheet is uncontrolled by default. To drive it yourself — open it from a row action, or close it after a mutation resolves — pass open and onOpenChange.

const [open, setOpen] = useState(false);

<Sheet open={open} onOpenChange={setOpen}>
  <SheetContent>
    {/* … */}
    <SheetFooter>
      <Button onClick={() => setOpen(false)}>Done</Button>
    </SheetFooter>
  </SheetContent>
</Sheet>;

Reference

Sheet

Root container. Extends base-ui Dialog.Root props.

PropTypeDefaultDescription
defaultOpenbooleanfalseInitial open state (uncontrolled)
openbooleanOpen state (controlled)
onOpenChange(open: boolean) => voidFires when the open state changes
modalbooleantrueTrap focus and block the page behind it

SheetTrigger

Opens the sheet. Extends base-ui Dialog.Trigger props. Pass render to use a Button (or any element) as the trigger.

PropTypeDefaultDescription
renderReactElementElement to render as the trigger

SheetContent

The drawer surface. Extends base-ui Dialog.Popup props. Renders its own portal, backdrop, and close button.

PropTypeDefaultDescription
side"top" | "right" | "bottom" | "left""right"Edge the sheet is anchored to and slides in from
size"sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "full""sm"Width on sm+ screens; applies to left/right sides only
showCloseButtonbooleantrueRender the floating close button in the top-right corner
classNamestringMerged onto the popup

SheetHeader

A flex flex-col container with padding for the title and description. Extends div props.

SheetTitle

The accessible title. Extends base-ui Dialog.Title props.

SheetDescription

Supporting text under the title, wired as the dialog’s accessible description. Extends base-ui Dialog.Description props.

SheetFooter

A flex flex-col container pinned to the bottom via mt-auto, for actions. Extends div props.

SheetClose

Closes the sheet. Extends base-ui Dialog.Close props. Pass render to use a Button as the close action.

PropTypeDefaultDescription
renderReactElementElement to render as the close control