# Slider

**Maturity:** experimental

A user-draggable control for choosing a single number within a bounded range — the canonical glass slider.

## Import

```tsx
import { Slider } from "@liquidify/react/slider"
```

## Props

- `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.
- `defaultValue`: `number | undefined`; default ``min``. Uncontrolled seed for the internal value (ignored once {@link SliderProps.value} is supplied). Clamped into `[min, max]`.
- `disabled`: `boolean | undefined`. When `true`, the slider is dimmed (fill dimmed + thumb greyed), removed from the tab order (`tabIndex={-1}`), and all pointer / keyboard interaction is suppressed. Since the root is a `<div role="slider">` (no native `disabled`), this sets `aria-disabled` plus a `data-disabled` styling hook.
- `labelProps`: `LabelProps | undefined`. Per-instance typography override for the bound labels, forwarded to the internal {@link Text} (ADR-0028). Token-backed axes only; the HIG default is `variant="footnote"` / `color="secondary"`. Applies only when a bound label is a string/number — an `<Icon>` / element bound passes through unwrapped.
- `max`: `number | undefined`; default ``1``. Upper bound of the value range.
- `maxLabel`: `ReactNode`. Trailing bound label for `variant="bounds"` — an `<Icon>` / `ReactNode` flanking the shortened track (the SwiftUI `maximumValueLabel` analogue). Decorative; it does not supply the accessible name.
- `min`: `number | undefined`; default ``0``. Lower bound of the value range.
- `minLabel`: `ReactNode`. Leading bound label for `variant="bounds"` — an `<Icon>` / `ReactNode` flanking the shortened track (the SwiftUI `minimumValueLabel` analogue). Decorative; it does not supply the accessible name.
- `onChange`: `((next: number) => void) | undefined`. Fires with the next clamped/snapped number whenever the value moves — pointer jump, drag, or a keyboard step. Always called, in both controlled and uncontrolled modes.
- `onEditingChanged`: `((editing: boolean) => void) | undefined`. Fires `true` on press / drag start and `false` on release — the SwiftUI `onEditingChanged` analogue.
- `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`.
- `step`: `number | undefined`; default ``0` (continuous)`. Snap increment. `0` is continuous (free movement); a positive value snaps the committed value to the nearest `min + round((raw - min) / step) * step` and drives the `stepped` keyboard increment.
- `tint`: `LiquidTintValue | undefined`; default ``"blue"``. System-accent of the minimum-track fill (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 the slider fill is system blue, so Slider defaults to `"blue"` (unlike Toggle's green).
- `value`: `number | undefined`. Controlled value. Passing this switches Slider to controlled mode: the rendered value always reflects this prop (clamped into `[min, max]`) and the consumer owns it via {@link SliderProps.onChange}.
- `variant`: `SliderVariant | undefined`; default ``"plain"``. The init-form family of the slider ({@link SliderVariant}), resolved via the `data-variant` CSS selector.

## SwiftUI mapping

- ``value: Binding<V>`` → ``value` (controlled) / `defaultValue` (uncontrolled seed)` (direct): The controlled-value triad (ADR-0015); a `Binding` splits into the controlled `value` + `onChange`, or the uncontrolled `defaultValue`.
- ``in: ClosedRange<V>`` → ``min` / `max`` (direct): The closed range's bounds (defaults `0` / `1`).
- ``step: V.Stride`` → ``step` (+ `variant="stepped"`)` (direct): Snap increment; presence of a positive `step` drives the `stepped` variant.
- ``label: () -> Label`` → `accessible label (`aria-label` / `aria-labelledby`)` (direct): SwiftUI's label is the accessible name; Slider renders no visible label text of its own.
- ``minimumValueLabel: () -> ValueLabel`` → ``minLabel`` (direct): Leading bound label for `variant="bounds"`; an `<Icon>` / `ReactNode`. A string/number renders through the `Text` primitive (`variant="footnote"`, `color="secondary"`); an `<Icon>`/element passes through unwrapped (ADR-0028).
- ``maximumValueLabel: () -> ValueLabel`` → ``maxLabel`` (direct): Trailing bound label for `variant="bounds"`; an `<Icon>` / `ReactNode` (same `Text` routing as `minLabel`).
- ``.font(_:)` / `.foregroundStyle(_:)` on the bounds` → ``labelProps` (`Pick<TextProps, …>`)` (direct): Per-instance typography override forwarded to the internal `Text` of both bound labels (token-backed axes only; ADR-0028). Applies only to string/number bounds.
- ``onEditingChanged: (Bool) -> Void`` → ``onChange(next: number)` + optional `onEditingChanged?(editing: boolean)`` (direct): `onChange` fires the next clamped/snapped value on every move; `onEditingChanged` (optional) fires `true` on press / drag start and `false` on release, mirroring SwiftUI exactly.
