Xzero UI
Pro library

Sheet stackPro

Nested sheets that stack with depth, drag to dismiss, and become stacked dialogs on wide screens.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/sheet-stack
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/sheet-stack

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { Sheet, SheetStack, SheetTrigger, useSheetStack } from "@/components/xzero/sheet-stack/sheet-stack";

function SaveButton() {
  const { close } = useSheetStack();
  return <button type="button" onClick={close}>Save</button>;
}

export function Settings() {
  return (
    <SheetStack>
      <SheetTrigger sheet="settings">Settings</SheetTrigger>

      <Sheet id="settings" title="Settings">
        <SheetTrigger sheet="notifications">Notifications</SheetTrigger>
      </Sheet>

      <Sheet id="notifications" title="Notifications" footer={<SaveButton />}>
        <label><input type="checkbox" defaultChecked /> Email me about mentions</label>
      </Sheet>
    </SheetStack>
  );
}

API reference

SheetStack

Holds the stack of open sheets and renders the layer they appear in. Declare every Sheet inside one SheetStack.

PropTypeDefaultDescription
children (required)ReactNode–Page content, triggers, and Sheet declarations.
stackstring[]–Controlled ids of open sheets, bottom first. Leave undefined for uncontrolled use.
defaultStackstring[][]Sheets open at first when uncontrolled.
onStackChange(stack: string[]) => void–Called when sheets are pushed or popped.
mode"auto" | "sheet" | "dialog""auto"auto picks bottom sheets below breakpoint and centered dialogs above it.
breakpointnumber640Width in px of the viewport, or the container when contained, where auto switches to dialogs.
containedbooleanfalseFill the nearest positioned ancestor instead of the viewport.

Sheet

One level of the stack. Renders nothing until its id is pushed.

PropTypeDefaultDescription
id (required)string–Id used by push, popTo, SheetTrigger, and the stack array.
title (required)string–Heading and accessible name.
descriptionstring–A line under the title, wired as the dialog description.
children (required)ReactNode–Scrolling body content.
footerReactNode–A row pinned under the scrolling body, such as the primary action.
backLabelstring–Label for the back button of a sheet opened from this one. Defaults to title.
dismissiblebooleantrueAllow drag and fling to dismiss.
classNamestring–Class on the panel.
refRef<HTMLDivElement>–The panel element.

SheetTrigger

A button that opens a sheet on top of the stack. Takes every button attribute.

PropTypeDefaultDescription
sheet (required)string–Id of the sheet to push.
refRef<HTMLButtonElement>–The button element.
...propsButtonHTMLAttributes<HTMLButtonElement>–Forwarded to the button. Call preventDefault in onClick to skip the push.

useSheetStack

Returns { stack, push, pop, popTo, close } for buttons inside or beside the sheets. Throws outside SheetStack.

No props.

Keyboard interactions

KeysAction
EscapeCloses the top sheet only.
Tab / Shift+TabCycles focus inside the top sheet.
Enter / SpaceRuns back, close, and trigger buttons.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in surfaces

Guidance for AI tools

Sheet stack: Nested sheets that stack with depth, drag to dismiss, and become stacked dialogs on wide screens. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components