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.

Stepper

A user-tappable control for incrementing or decrementing a numeric value by a fixed step — the canonical glass stepper.

import { Stepper } from "@liquidify/react/stepper"

Overview

Basic Stepper

A focused starting point showing Stepper with its essential configuration.

API

PropTypeDefaultDescription
childrenReactNode—Optional visible label content, rendered next to the capsule in a row — the SwiftUI `label:` closure / `init(_ titleKey:)` analogue (`<Stepper aria-label="Quantity">Quantity</Stepper>`). The accessible name is **not** sourced from here; supply `aria-label` / `aria-labelledby` for the screen-reader name (the segment buttons derive theirs from it). children role: `label`.
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.
defaultValuenumber | undefinedmin` (when bounded), else `0Uncontrolled seed for the internal value (ignored once {@link StepperValueProps.value} is supplied). Clamped into `[min, max]`. Absent in callback mode — no value binding exists.
disabledboolean | undefined—When `true`, both segments are inert; `aria-disabled` + `data-disabled` on the root; `disabled` on each segment button; `tabIndex={-1}` on the root.
labelPropsLabelProps | undefined—Per-instance typography override for the visible label, forwarded to the internal {@link Text} (ADR-0028). Token-backed axes only (`variant`, `weight`, `color`, `tint`, `tracking`, …); the HIG default is `variant="body"` / `color="primary"`. Applies only when {@link StepperCommonProps.children} is a string/number — a label element the consumer passes is rendered as-is.
maxnumber | undefined`undefined` (unbounded)Upper bound of the value range. Absent in callback mode — there is no range to bound.
minnumber | undefined`undefined` (unbounded)Lower bound of the value range. Absent in callback mode — there is no range to bound.
onChange((next: number) => void) | undefined—Fires with the next clamped value whenever the value changes. Called in both controlled and uncontrolled modes. Absent in callback mode — no value binding exists.
onDecrement(() => void) | undefined—See {@link StepperValueProps.onIncrement}. Fires on each `−` press.
onEditingChanged((editing: boolean) => void) | undefined—Fires `true` on segment `pointerdown`, `false` on `pointerup` / `pointercancel` — the SwiftUI `onEditingChanged` analogue.
onIncrement(() => void) | undefined—Not on the value branch — callback-only mode is mutually exclusive with a value binding (charter §6). Fires on each `+` press.
refRef<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`.
stepnumber | undefined1Increment / decrement magnitude. A zero, `NaN`, non-finite, or negative `step` coerces to the default `1` (a negative `step` no longer reverses direction). Absent in callback mode — there is no value to step.
valuenumber | undefined—Controlled value. Passing this switches Stepper to controlled mode: the rendered value always reflects this (clamped) and the consumer owns it via {@link StepperValueProps.onChange}. Absent in callback mode — no value binding exists.

Guidelines

Do
  • Use Stepper 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 Stepper 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

Stepper 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-bg-primary#ffffff
--lq-color-label-primaryComponent-defined value
--lq-color-label-secondaryComponent-defined value
--lq-color-label-tertiaryComponent-defined value
--lq-color-separatorrgba(60, 60, 67, 0.14)
--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-opacity-faint0.3
--lq-opacity-muted0.4
--lq-radius-pill9999rem
--lq-space-0.0625rem0.125rem0.25rem0.5rem0.75rem1rem1.25rem1.5rem2rem2.5rem3rem3.5rem
--lq-stepper-capsule-hComponent-defined value
--lq-stepper-disabled-opacityComponent-defined value
--lq-stepper-divider-wvar(--lq-space-2)
--lq-stepper-padvar(--lq-space-4)
--lq-stepper-segment-wcalc(var(--lq-space-40) + var(--lq-space-4))

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