GitHubGitHub
← All components
Overlays / component

Sheet

A dialog that becomes a sheet on phones — full-screen for forms, or a bottom dock for confirms — with the header and footer pinned while the body scrolls between them.

FullDockDesktop card

Narrow the window below 480px to see the phone presentation.

<Sheet open={editing} variant="full" title="Edit project" onclose={close}>  <Field label="Name"><TextInput bind:value={name} /></Field>  {#snippet footer()}<Button variant="primary">Save</Button>{/snippet}</Sheet>

Installation

pnpm add @chanrg/4ui

Import the stylesheet once, at the root of your app:

import '@chanrg/4ui/styles.css';

Usage

import { Sheet } from '@chanrg/4ui';<Sheet open={editing} variant="full" title="Edit project" onclose={close}>  <Field label="Name"><TextInput bind:value={name} /></Field>  {#snippet footer()}<Button variant="primary">Save</Button>{/snippet}</Sheet>

Composition

Use the following composition to build a sheet:

Sheet
├── header (snippet)
├── children
└── footer (snippet)

Bottom dock

Use variant="dock" for confirms and small pickers; on a phone it rises from the bottom edge.

Narrow the window below 480px to see it rise from the bottom edge.

<Sheet open={confirming} variant="dock" title="Delete service" onclose={close}>  <p>This cannot be undone.</p>  {#snippet footer()}<Button variant="danger">Delete</Button>{/snippet}</Sheet>

API reference

Props

PropTypeDefaultDescription
openbooleanfalseVisibility.
variantfull | dockfullPhone presentation: 100dvh sheet, or an 85dvh bottom dock.
sizesm | md | lgmdDesktop width cap; on phones the sheet is full-bleed.
showHandlebooleantrueGrab affordance on the dock variant.
header / children / footerSnippetTitle row, the scrolling body, and the pinned action row.
closeOnBackdrop / oncloseboolean / () => voidtrue / —Backdrop and Escape both request a close.

CSS variables

VariableDescription
--4ui-surfacePrimary component surface.
--4ui-textPrimary foreground color.
--4ui-borderDefault control and panel border.
--4ui-safe-bottomHome-indicator inset added under the sheet.

Accessibility

  • Focus is trapped inside the sheet and restored to the opener on close.
  • Escape closes; the dialog is labelled by its title.
  • The body is the only scrolling region, so the header and footer never scroll out of reach.

Dependencies

Icon, focus-trap