Noctis

Sheet

A panel that slides in from a screen edge. A trigger opens a portalled, modal surface that traps focus and dims the page behind it — composed from a header, a scrollable body, and a pinned footer.

Basic

A Sheet.Trigger opens the Sheet.Content. Compose the trigger from a Button through render so it inherits the button's look, hover, and focus; the content holds a Sheet.Header (with a Title, Description, and a corner Close), a scrollable Sheet.Body, and a Sheet.Footer whose actions close the panel through Sheet.Close.

Sides & sizes

Dock the panel to any edge with side on Sheet.Contentend (the default), start, top, or bottom; the panel slides in from that edge and start/end flip under RTL. size sets the cross-axis extent — sm, md (default), lg, xl, or full — which reads as width for side sheets and height for top/bottom sheets.

Stacked sheets

Sheets stack into layers, so a flow can drill deeper without ever leaving the panel — a list opens a detail, the detail opens an editor — and each step back peels one layer off. There are two ways to build a stack:

  • Static nesting — render a Sheet.Root inside another sheet's Sheet.Content. Use it when the depth is fixed and known at author time.
  • Imperative stack — for dynamic depth (push a layer in response to a click, from anywhere), hold a manager with useSheetStack, render it with <SheetStack manager={…}>, and drive it with push / pop / close. Each layer is a real nested Base UI dialog, so focus trapping, scroll-lock, and Escape ordering across the stack are handled for you, and panels behind peek out by depth.

The manager is dependency-injected through <SheetStack>, so any descendant reaches it with useSheetStackContext — a button inside one layer can push the next without prop threading. A layer's content is just the inner parts (Sheet.Header / Body / Footer and a Sheet.Close); the stack supplies the surrounding Root and Content.

The manager (SheetStackManager) exposes entries and depth for reading the stack, and push(entry) (returns the layer's key; reusing a key moves that layer to the top), pop() (hide the top layer), close(key) (hide a layer and everything above it), replace(entries) (swap the whole set), reset() (hide every layer), and remove(key) (hard-unmount, skipping the exit animation) for driving it. pop / close / reset only hide layers so they animate out; the unmount follows once the exit finishes.

Anatomy

Compose a sheet from its parts. Sheet.Root owns the open state (it accepts every Base UI Dialog.Root prop — open, defaultOpen, onOpenChange, modal). Modal by default: focus is trapped, the page is scroll-locked, and the rest of the document is inert.

  • Sheet.Root — owns the open state; renders no element of its own. Nest a Sheet inside another sheet's Content to stack them — panels behind peek out by depth and Base UI keeps focus and Escape ordering correct.
  • Sheet.Trigger — opens the sheet. Style it directly or compose a Button through render.
  • Sheet.Content — the common composition: portal, backdrop, and panel in one. Props: side (default end), size (default md), and backdropClassName. Reach for Sheet.Portal + Sheet.Backdrop + Sheet.Popup directly only when you need to customize the portal or backdrop wiring.
  • Sheet.Header — the panel's top region for the Title, Description, and corner actions, separated from the body by a divider.
  • Sheet.Body — the scrollable middle region; it grows to fill and scrolls its overflow so the header and footer stay put.
  • Sheet.Footer — the panel's bottom region, pinned to the base, typically holding the primary and secondary actions.
  • Sheet.Title + Sheet.Description — the panel's accessible name and supporting copy, linked to the popup via aria-labelledby and aria-describedby.
  • Sheet.Close — closes the nearest sheet. Renders a bare button with no styling of its own, so it composes with any Button through render — a ghost icon button for the corner dismiss, a secondary or primary button for a footer action. Give it an aria-label (or visible text) for the accessible name.

Every rendered part carries a data-slot (noctis-sheet-trigger, noctis-sheet-backdrop, noctis-sheet-viewport, noctis-sheet-popup, noctis-sheet-close, noctis-sheet-header, noctis-sheet-body, noctis-sheet-footer, noctis-sheet-title, noctis-sheet-description) for host-side styling — the popup also carries data-side and data-size. Pair it with the Base UI state attributes (data-open, data-closed, data-starting-style, data-ending-style). The popup renders through Surface at elevated elevation, so controls inside re-derive off that base and separate cleanly.

Keyboard

KeyAction
Enter / SpaceOn the trigger: open the sheet and move focus into the panel.
Tab / Shift + TabMove focus to the next / previous element, trapped within the open panel.
EscClose the panel and return focus to the trigger; in a stack, pop the top sheet first.

A click on the dimmed backdrop also closes the sheet, stepping back one level in a stack. Disabled and inert content behind the panel stays unreachable while the sheet is open.

Design tokens

Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every sheet in that region retunes — e.g. .editor { --noctis-sheet-popup-peek-offset: 1.5rem; } widens how far stacked panels fan out beneath it. Knobs that aren't minted are reached through the part's data-slot. See Customization for the full override ladder and Tokens for the whole graph.

Token

API reference

Generated from the component's types — every prop, type, default, and description comes straight from the source. Each part gets its own table; parts that only forward to Base UI's Dialog list just the props they pass through. Expand a row for the full type and description.

Sheet.Root

No props of its own — forwards to the underlying Base UI part.

Sheet.Trigger

Prop

Sheet.Portal

Prop

Sheet.Backdrop

Prop

Sheet.Viewport

Prop

Sheet.Popup

Prop

Sheet.Content

Prop

Sheet.Close

Prop

Sheet.Header

Prop

Sheet.Body

Prop

Sheet.Footer

Prop

Sheet.Title

Prop

Sheet.Description

Prop