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

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

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

Overview

Basic Toggle

A focused starting point showing Toggle with its essential configuration.

API

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 | undefinedfalseUncontrolled 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 | undefinedfalseTri-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 | undefinedregularSize 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" | undefinedswitchVisual 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.

Guidelines

Do
  • Use Toggle when its semantics match the content or action.
  • Keep labels concise, specific, and consistent with the surrounding interface.
  • Test the component with keyboard navigation, zoom, and both color schemes.
Don't
  • Do not use Toggle as a visual substitute for a different semantic element.
  • Do not rely on color or an icon alone to communicate essential meaning.
  • Do not override the component tokens with fixed values unless the product theme requires it.

Accessibility

Toggle supports the documented keyboard interactions below.

Keyboard
  • Press Tab to move focus to the control.
  • Use the control's documented activation keys without trapping focus.
  • Provide an accessible name whenever the visible label is absent.

Tokens

NameValue
--lq-color-accent#007aff
--lq-color-action-secondaryrgba(120, 120, 128, 0.16)
--lq-color-bg-primary#ffffff
--lq-color-separatorrgba(60, 60, 67, 0.14)
--lq-color-system-green-default-dark#30d158
--lq-color-system-green-default-light#34c759
--lq-duration-0ms80ms120ms150ms250ms350ms500ms
--lq-easing-cubic-bezier(0.25, 0.1, 0.25, 1)cubic-bezier(0, 0, 0.2, 1)cubic-bezier(0.4, 0, 1, 1)cubic-bezier(0.175, 0.885, 0.32, 1.275)cubic-bezier(0.25, 0.46, 0.45, 0.94)
--lq-glass-440.71.15var(--lq-segmented-control-indicator-blur)calc(var(--lq-glass-material-blur) * 8)var(--lq-shadow-presentational)
--lq-hit-target-touch2.75rem
--lq-lens-progressResolved by the active Liquidify theme
--lq-lens-xResolved by the active Liquidify theme
--lq-radius-0.25rem0.375rem0.5rem0.625rem0.875rem1.125rem1.375rem9999rem
--lq-radius-pill9999rem
--lq-shadow-ambient-0 0.125rem 0.375rem rgba(0, 0, 0, 0.10)0 0.5rem 1.375rem rgba(0, 0, 0, 0.20)0 0.75rem 1.75rem rgba(0, 0, 0, 0.14)
--lq-space-0.0625rem0.125rem0.25rem0.5rem0.75rem1rem1.25rem1.5rem2rem2.5rem3rem3.5rem

Key features

  • Liquid material

    Uses Liquidify surfaces and theme-aware design tokens.

  • Typed API

    Provides a typed React API with generated prop documentation.

  • Accessible by default

    Preserves semantic structure, focus visibility, and assistive-technology state.

Resources

  • Source
  • Markdown
  • JSON
  • Storybook
Components