Skip to content
Liquidify
HomeDocsComponentsExamplesPlayground
⌘K
(opens in new tab)
Liquidify

Accessible React controls with a CSS and SVG material engine.

Product

ComponentsExamplesPlaygroundPackages

Learn

DocumentationGetting startedConceptsAI resources

Project

CommunityShowcaseVersionsGitHub

Independent open-source software. Not affiliated with or endorsed by Apple Inc.

LicenseBrand

Component catalog

Browse the public controls by interaction purpose. Every result links to generated API facts, accessibility behavior, source, and exhaustive stories.

Toggle (checkbox variant)

A user-flippable control for a single boolean setting — the canonical glass switch.

controlsexperimentalReact
Toggle (checkbox variant)Open live story

Overview

A user-flippable control for a single boolean setting — the canonical glass switch.

Experimental contract

This API may change before the next stable release. Pin the package version when evaluating it.

checkbox is a documented Toggle variant.

It is intentionally not published as a separate package export.

Example

Install the package and import the component from its public entry point.

pnpm add @liquidify/react
import { Toggle } from "@liquidify/react/toggle"

This minimal form confirms the public import. Use the curated examples for application-shaped composition and Storybook for exhaustive states.

Open editable application examples

API reference

PropTypeDefaultDescription
checkedboolean | undefined—Controlled checked state. Passing this switches Toggle to controlled mode: the rendered state always reflects this value and the consumer owns it via {@link ToggleProps.onChange}.
childrenReactNode—Visible label content for the `"button"` variant (the iOS `.toggleStyle(.button)` analogue). When supplied with `variant="button"`, this content renders inside the pill capsule — an icon glyph, text, or an icon+text pair — and the capsule sizes to it. Ignored — documented, not silent — for the default `"switch"` variant (a switch renders no visible text of its own). children role: `label` (charter §8).
classNamestring | 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.
defaultCheckedboolean | undefined`false`Uncontrolled seed for the internal checked state (ignored once {@link ToggleProps.checked} is supplied).
disabledboolean | undefined—When `true`, sets the native `disabled` attribute on the `<button>`: the switch is removed from the tab order, all interaction is suppressed, and a `data-disabled` styling hook dims the surface. `aria-disabled` is NOT set — the native attribute provides full-suppression semantics.
indeterminateboolean | undefined`false`Tri-state DISPLAY overlay for `variant="checkbox"` (the AppKit `NSButton.allowsMixedState` / `NSControl.StateValue.mixed` lineage) — a **web-only extension** with no SwiftUI `Toggle` equivalent. When `true` the box announces `aria-checked="mixed"` (`data-state="mixed"`) and paints a dash glyph, while the underlying value contract stays boolean: `checked` / `onChange` never carry `"mixed"`. Activating a mixed box commits a concrete `onChange(true)` (the WAI-ARIA APG default). Ignored — documented, not silent — under `"switch"` / `"button"` (a switch has no tri-state).
labelPropsLabelProps | undefined—Per-instance typography override for the `"button"`-variant label, forwarded to the internal {@link Text} (ADR-0028). Token-backed axes only; the HIG default is `variant="body"` with `color="inherit"`, so the label keeps the button's state colour (accent unchecked, on-fill checked, grey disabled). Applies only when {@link ToggleProps.children} is a string/number — an icon or icon+text element passes through unwrapped.
onChange((checked: boolean) => void) | undefined—Fires with the next boolean whenever the switch flips — pointer tap, drag past the midpoint, or `Space` / `Enter`. Fires at most once per effective flip, in both controlled and uncontrolled modes; a cancelled gesture, a drag settling back on its starting side, a repeated same-value request, or a disabled interaction emits nothing (the shared no-op policy).
onClickMouseEventHandler<HTMLButtonElement> | undefined—Documented native passthrough (charter §1): fires before Toggle's internal flip on every click event dispatched to the root — a pointer tap's trailing click, the browser's own click synthesis on `Space`, or the programmatic click Toggle dispatches on `Enter`. `event.preventDefault()` suppresses that click's flip **and** the resulting {@link ToggleProps.onChange}. A plain pointer tap defers its commit to this click event (rather than committing in the pointer handlers), and `Enter` routes through a single dispatched click, so cancellation is uniform across the pointer and keyboard (`Space` / `Enter`) paths. A drag settle (past the midpoint) is the one exception: it commits synchronously in `onPointerUp`, so its trailing click is swallowed rather than re-evaluated — documented as NOT click-cancellable. Either way `onClick` still fires exactly once per interaction (the synthesised-click swallow is preserved for drags). Toggle has no `onPress` — its activation IS the value change.
refRef<HTMLButtonElement> | undefined—Forwarded ref to the rendered element — the native `<button role="switch">` track itself (charter §4 truthful ref; there is no wrapper element to diverge from this type).
sizeToggleSize | undefined`"regular"`Size of the switch — the `small · regular` subset of the canonical {@link SizedControlProps.sizesize scale} (the SwiftUI `.controlSize(_:)` analogue, ADR-0018). Resolved to geometry via `data-size` attribute selectors in `styles.css`; the root stamps `data-size` **unconditionally** (the Button pattern), so both values are always addressable. `mini` / `large` / `xlarge` are excluded — Apple ships no large switch.
tintLiquidTintValue | undefined`"green"` (`"accent"` under `variant="checkbox"`)System-accent of the on-track (the SwiftUI `.tint(_:)` analogue), drawn from the restricted {@link LIQUID_COLORS } palette and applied via the `data-tint` attribute selector in CSS. Per Apple HIG a switch's "on" track is system green, so Toggle defaults to `"green"`. For `variant="button"` the `tint` is the button accent — the checked fill and the label colour in both checked and unchecked — following the palette (default systemBlue). Disabled greys the text but keeps the checked tint fill. For `variant="checkbox"` the HIG default is the app **`"accent"`** (system blue) — the checked/mixed box fill — diverging from the switch's green (open question O1, resolved: `"checkbox"` auto-overrides the green default unless an explicit `tint` is supplied). An explicit `tint` always wins.
variant"button" | "switch" | "checkbox" | undefined`"switch"`Visual style of the toggle. `"switch"` (default) renders the sliding-thumb switch; `"button"` renders a pill capsule (the SwiftUI `.toggleStyle(.button)` analogue) used for formatting toolbars and single-option on/off buttons — the whole capsule fills with the tint accent when on; `"checkbox"` renders a small rounded-square glass box (leading) with a trailing `children` label (the macOS-family `CheckboxToggleStyle` analogue) — no sliding thumb, no liquid-lens. The checkbox box carries `role="checkbox"`, a structural state glyph (checkmark / dash / empty — ADR-0019), and defaults its `tint` to the app `"accent"` (system blue) per Apple HIG, diverging from the switch green.

SwiftUI mapping

The mapping describes naming and behavior without claiming framework equivalence.

SwiftUIReactRelationshipNotes
`isOn: Binding<Bool>``checked` (controlled) / `defaultChecked` (uncontrolled seed) + `onChange(next: boolean)`directThe controlled-value triad (ADR-0015); a `Binding` splits into the controlled `checked` + `onChange`, or the uncontrolled `defaultChecked`. `onChange` fires at most once per effective flip, in both modes — cancelled gestures, same-side settles, repeated same-value requests, and disabled interaction emit nothing (see `## Interaction`).
`.toggleStyle(.switch)` / `.toggleStyle(.button)` / `.toggleStyle(.checkbox)``variant: "switch" | "button" | "checkbox"`directThe style-protocol name is the value (charter §6); `"switch"` is the default sliding-thumb pill, `"button"` the pill capsule, `"checkbox"` the leading glass box + trailing label (`CheckboxToggleStyle`, macOS family — no iOS render).
`.tint(_:)``tint`directRestricted `LiquidColor` palette; default `"green"` (HIG switch-on divergence from the base `tint="accent"` default — documented in `## Tokens`). The `"checkbox"` variant's HIG default reads as **accent** (system blue), not green — auto-override vs. caller-set is open question O1.
`NSButton.allowsMixedState` / `NSControl.StateValue.mixed` (AppKit, `checkbox` only)`indeterminate` → `aria-checked="mixed"` + dash glyphweb-only**Web-only extension** — no SwiftUI `Toggle` equivalent. A controlled *display* overlay: the value contract stays boolean (`checked`/`onChange`), `indeterminate` only drives the mixed rendering + announcement. Activating a mixed box commits a concrete `onChange(true)` (APG default; the committed boolean is open question O3). Ignored — documented, not silent — under `"switch"`/`"button"`.
`.controlSize(_:)``size: ToggleSize` (`Extract<Size, "small" | "regular">`)direct`mini`/`large`/`xlarge` excluded — Apple ships no large switch. `data-size` is stamped unconditionally on the root (Button pattern); default `"regular"`.
`.disabled(_:)``disabled`directShape N: native `disabled` + `data-disabled`; no `aria-disabled` (full-suppression semantics, charter §3).
`Toggle(_:isOn:) { label }` closure`children`directVisible label under `variant="button"` and `variant="checkbox"` (icon, text, or icon+text; trailing the box under `"checkbox"`); ignored — documented, not silent — under `"switch"` (charter §8 `children` role: label).
label-view modifiers (`.bold()`, …)`labelProps` (`Pick<TextProps, …>`)directPer-instance typography override forwarded to the internal `Text` (ADR-0028); token-backed axes only, applies only to string/number `children`.
`.accessibilityLabel(_:)` / `.labelsHidden()` (nameless switch)`aria-label` / `aria-labelledby`directRequired accessible-name source under `variant="switch"` — the control renders no text of its own. Under `"button"`/`"checkbox"` a text `children` label supplies the name, but an icon-only/empty label still requires an explicit `aria-label` / `aria-labelledby`.
— (web-only)`className`web-onlyOverridable glass-surface class (`LiquidBaseProps`, inherited).
— (web-only)`ref: Ref<HTMLButtonElement>`web-onlyForwarded to the native `<button role="switch">` track — the charter-truthful ref target (charter §4).
— (web-only)`onClick?: MouseEventHandler<HTMLButtonElement>`web-onlyDocumented native escape hatch (charter §1): fires before the internal flip on every click event (pointer tap, Space); `event.preventDefault()` suppresses the flip and `onChange`. Toggle has no `onPress` — its activation IS the value change (charter §1 rule 4).

Keyboard

  • Keyboard

    Keyboard: switch/button — Space / Enter flip via the same sequence; Tab focuses; arrows do nothing. checkbox — Space toggles per the APG checkbox pattern; whether Enter also toggles (Toggle's cross-variant behaviour) or is dropped to match the APG letter (Space-only) is open question O2. Tab focuses; arrows do nothing (a lone checkbox is not a radiogroup — no roving tabindex).

Tokens

  • --lq-color-accent
  • --lq-color-action-secondary
  • --lq-color-bg-primary
  • --lq-color-separator
  • --lq-color-system-green-default-dark
  • --lq-color-system-green-default-light
  • --lq-duration-
  • --lq-easing-
  • --lq-glass-
  • --lq-hit-target-touch
  • --lq-lens-progress
  • --lq-lens-x
  • --lq-radius-
  • --lq-radius-pill
  • --lq-shadow-ambient-
  • --lq-space-

Resources

SourceMarkdownJSONStorybook
Components