# Sheet

**Maturity:** experimental

A modal surface presented from the bottom edge of the viewport that the consumer fills with arbitrary content.

## Import

```tsx
import { Sheet } from "@liquidify/react/sheet"
```

## Props

- `children`: `ReactNode`. The sheet content — rendered inside the glass card (charter §8 slot role: content).
- `className`: `string | undefined`. Optional additional CSS class merged into the glass surface class. The supported per-instance customisation seam: override any `--lq-*` custom property from this class's CSS — the token cascade the engine reads (ADR-0004). No raw inline style is involved, so this stays ADR-0003 clean.
- `cornerRadius`: `SheetCornerRadius | undefined`; default ``"22"``. Top corner radius of the card, as a `--lq-radius-*` token key — SwiftUI `.presentationCornerRadius`.
- `defaultOpen`: `boolean | undefined`. Uncontrolled seed for the open state (default `false`).
- `detents`: `readonly SheetDetent[] | undefined`; default ``["large"]``. Available resting heights (SwiftUI `.presentationDetents`). The sheet opens at the FIRST detent; dragging the top handle snaps between detents, and dragging past the smallest one dismisses the sheet (when `dismissible`).
- `dismissible`: `boolean | undefined`. Whether Escape, a scrim tap, and a drag past the smallest detent dismiss the sheet (`interactiveDismissDisabled`, inverse polarity). Escape / scrim are forwarded to Overlay; drag-dismiss is gated here. Defaults to `true`.
- `dragIndicator`: `SheetDragIndicator | undefined`; default ``"visible"``. Whether the drag indicator (grabber) is shown — SwiftUI `.presentationDragIndicator`. The pan region (the top edge) stays draggable either way; only the grabber pill toggles.
- `material`: `"frosted" | "regular" | "clear" | undefined`; default `enclosing `<Material default>`, else `"regular"``. Material of the glass surface — `frosted · regular · clear` (§06). Forwarded to the engine, which resolves the chain `prop ?? <Material default> ?? "regular"`, so a bare surface inherits the enclosing provider default.
- `onOpenChange`: `((open: boolean) => void) | undefined`. Fires with the next open state on every close path (Escape, scrim tap, drag past the smallest detent).
- `open`: `boolean | undefined`. Controlled open state. Passing it switches Sheet to controlled mode.
- `perf`: `"low" | "high" | undefined`; default `derived from `<Backdrop type>`, else `"low"``. Perf budget of the glass surface (ADR-0006/0007). Forwarded to the engine as `data-glass-perf`; `"high"` opts this surface into the edge-lensing filter. When omitted, derives from the enclosing `<Backdrop type>` (§04).
- `ref`: `Ref<HTMLDivElement> | undefined`. Forwarded ref to the rendered element — the component's native root (or the merged child element on a component that opts into {@link SlottableProps}). Generic over `E` (charter `docs/api-conventions.md` §4 rule 1, default `HTMLElement`) so a component with a polymorphic root (Link's navigation / action mode union, Text's `as`) can instantiate the concrete element per variant instead of leaving every consumer with a widened `Ref<HTMLElement>`. A component that does not narrow simply inherits the `HTMLElement` default — source-compatible with every pre-existing non-generic `extends ControlProps`.

## SwiftUI mapping

- ``isPresented: Binding<Bool>`` → ``open` / `defaultOpen` / `onOpenChange`` (direct): presentation triad (ADR-0015), forwarded to `Overlay` via the shared `useControllableState` machine (§6.1)
- ``content: () -> View`` → ``children`` (direct): the sheet body (charter §8 slot role: content)
- ``.interactiveDismissDisabled(_)`` → ``dismissible`` (direct): inverse polarity (consistent with Overlay/Alert/ActionSheet) — gates Escape, scrim, **and** drag-dismiss
- ``.presentationDetents([.medium, .large])`` → ``detents: SheetDetent[]`` (direct): resting heights; opens at the first detent
- ``.fraction(0.6)`` → ``{ fraction: 0.6 }` detent` (direct): a fraction (0–1) of the viewport height
- ``.large` / a full sheet` → ``"full"` detent` (direct): 100 % of the viewport height
- ``.presentationDragIndicator(.hidden)`` → ``dragIndicator: "visible" | "hidden"`` (direct): shows / hides the grabber
- ``.presentationCornerRadius(_)`` → ``cornerRadius: "10" | "14" | "22"`` (direct): `--lq-radius-*` token key (ADR-0003 forbids a raw length)
- ``.presentationBackground` (material)` → ``material?` / `perf?`` (direct): `PresentationalProps` — the card's glass surface; the base is tint-free (P0.B6 — no `tint` axis; a sheet has no accent to adopt)
- `(no SwiftUI analogue)` → ``ref?`` (web-only): forwarded to the semantic root — the glass dialog card (`role="dialog"`); typed `Ref<HTMLDivElement>` (charter §4, narrowed to the concrete GlassPrimitive `<div>`); attached while the sheet is mounted, `null` while closed
- `(nameless surface)` → ``aria-label` / `aria-labelledby`` (direct): the accessible name for the dialog
