# Panel

**Maturity:** experimental

Wrap a related cluster of content behind one titled glass card, so a screen reads as distinct sections that let the backdrop lens through the surface — Apple's Liquid Glass container, as opposed to GroupBox's opaque grouped-background card.

## Import

```tsx
import { Panel } from "@liquidify/react/panel"
```

## Props

- `children`: `ReactNode` (required). The grouped content (`{ … }` content closure, children role: `content`) — content-agnostic: hosts `LabeledContent` rows, a `Toggle`, a `ProgressIndicator`, or a nested `Panel`/`GroupBox`.
- `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.
- `id`: `string | undefined`. Optional id forwarded verbatim to the `role="group"` glass root, so a consumer can target the surface from its own `aria-*` wiring. Panel's internal label id is generated separately and never collides with it.
- `label`: `ReactNode`. The card's title (`GlassPanel(label:)` / SwiftUI `GroupBox(_:content:)`). A `string` routes through the `TextLabel` guard into an internal `Text` (`variant="headline"`, `weight="semibold"`, `color="secondary"` by default, overridable per-instance via `labelProps`) carrying the id the root's `aria-labelledby` targets. A `ReactNode` (e.g. an icon+text composite) passes through unwrapped so the caller keeps ownership of its own typography and icon (`labelProps` has no effect on this shape). Omitted, or supplied as a non-renderable value (`false` / `null` / `true` / `""`), renders no label region and no `aria-labelledby` — an intentionally unnamed group.
- `labelProps`: `LabelProps | undefined`. Per-instance typography override for a `string` `label` (ADR-0028, charter §2) — spread last onto the internal `Text` so an explicit value wins over the `headline`/`semibold`/`secondary` default. No effect when `label` is a `ReactNode` (passes through `TextLabel` unwrapped) or omitted/non-renderable.
- `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.
- `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

- ``GlassPanel(label:)` / `GroupBox(_:content:)` — `String`/`LocalizedStringKey` title` → ``label?: string`` (direct): Routed through the `TextLabel` guard into an internal `Text` (ADR-0028). Mirrors `GlassPanel.swift`'s `Text(label)`.
- ``GroupBox(content:label:)` — custom `label` view` → ``label?: ReactNode`` (direct): Same `label` prop, union `string | ReactNode`; a node label renders verbatim — the caller composes its own icon+text pairing.
- ``.glassEffect(_ glass: Glass, in:)` — `glass` level` → ``material?: "frosted" | "regular" | "clear"`` (direct): `GlassPanel.swift`'s `glass: Glass` parameter → the public `material` knob (inherited from `PresentationalProps`, §06); forwarded to `useGlass`.
- ``.glassEffect(in: RoundedRectangle(cornerRadius: 24))` — clip shape` → `(fixed) `--lq-radius-22`` (direct): The surface corner radius; `--lq-radius-22` is the nearest existing scale token to the source's 24pt (no `--lq-radius-24` exists — same posture DisclosureGroup takes for its 20pt). Not a prop.
- ``.glassEffect(...)` perf tier` → ``perf?: GlassPerf`` (direct): Inherited from `PresentationalProps`; forwarded as `data-glass-perf`, derives from the enclosing `<Backdrop type>` when omitted.
- ``{ … }` content closure` → ``children: ReactNode` (required, children role: `content`)` (direct): Content slot, content-agnostic; rendered verbatim, no restyle/restructure.
- ``.font(_:)` / `.foregroundStyle(_:)` on a `string` title` → ``labelProps?: LabelProps`` (direct): Per-instance typography override seam (ADR-0028), spread **last** onto the string-`label` path's internal `Text`. No effect on a `ReactNode` or omitted label.
- ``GroupBoxStyle` / `.groupBoxStyle(_:)`` → `— (Out of scope v1)` (direct): Only the default surface is authored; no custom-style plumbing.
- ``controlSize`` → `—` (direct): Non-sizable; no `size` prop (see Sizes).
- ``.tint(_:)`` → `—` (direct): Panel has no accent surface; no `tint` prop (glass posture only).
- `*(no analogue — web-only)*` → ``ref?: Ref<HTMLDivElement>`` (web-only): `PanelProps extends PresentationalProps<HTMLDivElement>` (charter §4) — forwarded to the concrete `role="group"` glass root `<div>`.
