# ControlGroup

**Maturity:** experimental

Group related independent actions in one capsule, the React adaptation of SwiftUI ControlGroup.

## Import

```tsx
import { ControlGroup } from "@liquidify/react/control-group"
```

## Props

- `children`: `ReactNode` (required). Related controls, normally existing Button components. Each owns its onPress.
- `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.
- `disabled`: `boolean | undefined`; default `false`. Disable the group. A disabled ancestor always wins over a child's false.
- `label`: `ReactNode`; default `undefined`. Visible group label; use aria-label for an unnamed visual surface.
- `labelProps`: `LabelProps | undefined`; default `undefined`. Typography overrides for a string or number label (ADR-0028).
- `prominent`: `boolean | undefined`; default `false`. Use Button's prominent tint and enlarge the shared pill on hover/activation.
- `ref`: `Ref<HTMLFieldSetElement> | 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`.
- `separators`: `boolean | undefined`; default `true`. Show decorative dividers between adjacent actions.
- `size`: `ControlGroupSize | undefined`; default `"regular", or the enclosing ControlGroup size`. Default child size; an explicit child size wins.
- `tint`: `LiquidTintValue | undefined`. System-accent of the control — drawn from the RESTRICTED {@link LIQUID_COLORS} palette (the thirteen Apple system colours). **Orthogonal to a component's `variant`**: it recolours the accent the surface draws from (focus ring, tinted fill, selection) without changing its variant. Resolved via `data-tint` attribute selectors in CSS (tokens-only, ADR-0003).

## SwiftUI mapping

- ``init(content:)`` → ``children`` (direct): Existing Buttons; arbitrary native form controls retain native semantics.
- ``init(content:label:)`, `init(_:content:)`` → ``label`, `labelProps`` (direct): Optional visible ReactNode label; string/number typography through TextLabel.
- ``.labelsHidden()`` → ``aria-label` / `aria-labelledby`` (direct): Omit visible label and supply an accessible name. Explicit ARIA naming wins.
- ``.controlSize(_:)`` → ``size`` (direct): Inherited SizedControlProps; small, regular, large; regular default.
- ``.tint(_:)`` → ``tint`` (direct): Inherited TintableControlProps, defaults to child/system accent.
- ``.disabled(_:)`` → ``disabled`` (direct): Native fieldset plus Button context, ancestor disabled always wins.
- ``.buttonStyle(.glassProminent)` inspiration` → ``prominent`` (extension): Explicit group extension; shared tinted material and Button motion tokens, not a SwiftUI ControlGroup modifier.
- `Web presentation` → ``separators`` (direct): Optional decorative dividers; does not change action semantics.
- `Child `Button(action:)`` → `Child `Button onPress`` (direct): Existing API charter; no group activation callback.
- `Web composition` → ``className`, `ref`, `aria-describedby`` (direct): Ref targets HTMLFieldSetElement. No asChild.
