Skip to content
Documentation navigation
Setup

Components

Sheet

A modal panel anchored to a side of the viewport.

Basic example

Installation

Choose the package when you want centralized updates, or copy the source through the registry when you want local ownership.

Install the package, import its global tokens once, then use this exact subpath.

# install
pnpm add @constructive-io/ui
# app/globals.css
@import '@constructive-io/ui/globals.css';
# import
import { Sheet } from '@constructive-io/ui/sheet';

When to use

  • Use Sheet for settings, forms, and detail views that enter from an edge while leaving part of the current page visible.
  • Use Dialog for a centered interruption. Use Drawer when touch drag gestures and snap points are central to the task.

Basic usage

Compose SheetTrigger and SheetContent inside Sheet, then provide a title, description, body, and reachable close control. SheetContent supplies the portal, modal backdrop, motion, and icon close button.

npm source
tsx
'use client';
import { Button } from '@constructive-io/ui/button';
import { Input } from '@constructive-io/ui/input';
import { Label } from '@constructive-io/ui/label';
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from '@constructive-io/ui/sheet';
export function BasicSheetDemo() {
    return (<Sheet>
        <SheetTrigger render={<Button variant="outline"/>}>Edit organization</SheetTrigger>
        <SheetContent side="right">
          <SheetHeader>
            <SheetTitle>Organization settings</SheetTitle>
            <SheetDescription>Update the workspace details. Changes apply on save.</SheetDescription>
          </SheetHeader>
          <div className="grid gap-4 py-2">
            <div className="grid gap-2">
              <Label htmlFor="sheet-organization-name">Name</Label>
              <Input id="sheet-organization-name" defaultValue="Acme Corp"/>
            </div>
            <div className="grid gap-2">
              <Label htmlFor="sheet-organization-slug">Slug</Label>
              <Input id="sheet-organization-slug" defaultValue="acme"/>
            </div>
          </div>
          <SheetFooter>
            <SheetClose render={<Button />}>Save changes</SheetClose>
            <SheetClose render={<Button variant="outline"/>}>Cancel</SheetClose>
          </SheetFooter>
        </SheetContent>
      </Sheet>);
}

Controlled and uncontrolled visibility

Use defaultOpen when Sheet can own its initial visibility. Pass open and onOpenChange when application state is authoritative; the callback receives the next boolean value.

Controlled and uncontrolled visibility

Examples

Edge placementSet side on SheetContent to enter from the top, right, bottom, or left edge.
Stacked sheetsWrap related sheets in SheetStackProvider and nest each subsequent Sheet in the parent’s React tree. The provider tracks layer depth and pushes earlier panels aside.
Floating overlays inside a sheetPopover, Select, Dropdown Menu, and Tooltip use the sheet’s scoped portal automatically, so they stay interactive and above the modal.
Custom close control and motionSet showClose to false only when you provide a reachable SheetClose, and pass transition to adjust the panel motion without replacing dismissal behavior.

Accessibility

  • Give every SheetContent an accessible name with SheetTitle. Add SheetDescription when supporting context is useful, and give each form control a visible Label or another accessible name.
  • Keep a SheetClose inside the panel when showClose is false; the built-in icon close button already has an accessible name.
  • Base UI moves focus into the panel, traps focus for the top-level modal sheet, closes on Escape or outside press, and returns focus to the trigger.
  • Nested sheets keep the parent visible but make the newest sheet the active layer. Keep essential parent actions available again after the nested sheet closes.

API Reference

Constructive-specific behavior is listed here. Each part links to its inherited platform or primitive contract.

SheetStackProvider

Coordinates registration, dimensions, order, and push offsets for nested sheets.

PropTypeDefaultDescription
stackMode'cascade' | 'collapse''cascade'Indents every visible layer or moves lower sheets aside using the top sheet’s measured size.
useSheetStack

Returns the nearest stack context, or undefined outside SheetStackProvider. The context exposes sheets, measured sizes, stackMode, registration and size methods, isTopSheet, and getSheetsAbove.

useSheet

Returns isOpen, sheetId, depth, sheetsAbove, isTopSheet, and close for the current Sheet; it throws when used outside Sheet.

Sheet

Base UI Dialog root adapter that manages one sheet and registers it with an optional stack.

PropTypeDefaultDescription
openbooleanControlled visibility.
defaultOpenbooleanfalseInitial visibility in uncontrolled usage.
onOpenChange(open: boolean) => voidRuns when visibility changes.
sheetIdstringStable identifier used by SheetStackProvider; generated automatically when omitted.
modalboolean | 'trap-focus'trueControls top-level modal behavior; nested sheets override it to false so interacting with a nested layer does not dismiss its parent.
disablePointerDismissalbooleanfalsePrevents outside presses from closing a top-level sheet.

Also accepts Base UI Dialog props.

SheetPortal

Moves sheet parts into the configured portal container and establishes the elevated floating layer.

PropTypeDefaultDescription
containerHTMLElement | nullExplicit portal destination.
forceMountdeprecatedbooleanCompatibility prop retained as a no-op; Base UI manages mounting.

Also accepts Base UI Dialog props.

SheetOverlay

Styled Base UI backdrop for custom sheet compositions; SheetContent renders its own animated backdrop.

PropTypeDefaultDescription
asChilddeprecatedbooleanCompatibility prop retained as a no-op; Base UI uses render for composition.
forceMountdeprecatedbooleanCompatibility prop retained as a no-op; Base UI manages mounting.

Also accepts Base UI Dialog props.

SheetTrigger

Button that opens the sheet and provides the default focus-return target.

PropTypeDefaultDescription
renderReactElement | functionComposes trigger behavior onto another element.
asChildbooleanCompatibility composition prop; prefer render.
nativeButtonbooleantrueSet false when render or asChild produces a non-button element.

Also accepts Base UI Dialog props.

SheetClose

Button that closes the current sheet.

PropTypeDefaultDescription
renderReactElement | functionComposes close behavior onto another element.
asChildbooleanCompatibility composition prop; prefer render.
nativeButtonbooleantrueSet false when render or asChild produces a non-button element.

Also accepts Base UI Dialog props.

SheetContent

Animated panel composition with an optional backdrop, built-in close button, and scoped floating portal.

PropTypeDefaultDescription
side'top' | 'right' | 'bottom' | 'left''right'Selects the panel edge and motion direction.
transitionMotion TransitionOverrides the default panel transition.
overlaybooleantrueShows the backdrop for the top-level sheet without changing the root’s modal behavior.
showClosebooleantrueShows the accessible icon close button.
initialFocusboolean | RefObject<HTMLElement> | functionSelects the element focused when the sheet opens.
finalFocusboolean | RefObject<HTMLElement> | functionSelects the element focused after the sheet closes.
forceMountdeprecatedbooleanCompatibility prop retained as a no-op; Base UI and AnimatePresence manage mounting.
onInteractOutsidedeprecated(event: Event) => voidCompatibility prop retained as a no-op; observe dismissal with Sheet onOpenChange.
onPointerDownOutsidedeprecated(event: Event) => voidCompatibility prop retained as a no-op; observe dismissal with Sheet onOpenChange.
onEscapeKeyDowndeprecated(event: KeyboardEvent) => voidCompatibility prop retained as a no-op; observe dismissal with Sheet onOpenChange.
onFocusOutsidedeprecated(event: Event) => voidCompatibility prop retained as a no-op; observe dismissal with Sheet onOpenChange.

Also accepts Base UI Dialog props.

SheetHeader

Layout wrapper for SheetTitle and SheetDescription.

SheetFooter

Responsive action layout at the end of the sheet.

SheetTitle

Accessible heading that labels the sheet.

Also accepts Base UI Dialog props.

SheetDescription

Accessible supporting description for the sheet.

Also accepts Base UI Dialog props.

SHEET_INDENT

The 24-pixel offset applied per sheet above a panel in cascade mode.