Signal Formsa11y

Slider

Drag-to-pick numeric input. Single-thumb by default, optional dual-thumb range mode. A signal-forms native control — it implements FormValueControl, so [formField] binds straight to its value model. [(value)] works standalone, and template-driven [(ngModel)] / reactive forms keep working through Angular 22's forms bridge.

Installation

import { WrSlider } from 'ngwr/slider';

@Component({ imports: [WrSlider, FormsModule] })
export class MyComponent {
  protected volume = 35;
}

Single value

The default. Bind a number through any form mechanism.

<wr-slider [(value)]="volume" min="0" max="100" />
35
<wr-slider [(value)]='volume' min='0' max='100' />

Range

Set range to render two thumbs. The bound value is [low, high].

<wr-slider [(value)]="priceRange" range min="0" max="1000" step="50" />
200 – 800
<wr-slider [(value)]='priceRange' range min='0' max='1000' step='50' />

Step

The thumb snaps to the nearest multiple of step.

50
<wr-slider [(value)]='stepped' min='0' max='100' step='25' />

Disabled

35
<wr-slider [(value)]='volume' disabled />

Keyboard

The thumb is a real <button> with role='slider' — full keyboard support out of the box. Arrow keys step by step; Shift + arrow or PageUp / PageDown step by step × 10; Home / End jump to min / max.

Values outside the range, and `null`

[min] and [max] bound what the thumb can produce and where it can be drawn. A value written in from a form is clamped for the display only — the model keeps exactly what you set.

Set 155 on a slider bound with max="100" and the thumb parks at the top of its track and announces aria-valuenow="100", while control.value stays 155. The asymmetry is deliberate and matches wr-rating and wr-input-number: a thumb cannot render off its own track, so the display has no choice — but writing that clamp back into the model would delete the out-of-range value a Validators.max exists to report, and would mark a pristine form dirty on first paint. The first drag or arrow key commits an in-range number and the two agree from then on.

WrSliderValue is number | [number, number] — there is no empty state. A slider always points somewhere, so a value that is neither shape is ignored and the thumb stays where it was: control.reset(), which resets to null by default, leaves the thumb on the old position. Reset to a number instead — control.reset(0), or whatever your min is. In range mode, a scalar written to a two-thumb slider seeds the high thumb at max and, again, leaves the model holding the scalar you gave it until a thumb moves.

The reactive-forms guide has the same table for every value control, next to the two bridge behaviours that surprise people more: updateOn does not apply, and a { emitEvent: false } write does not repaint.

API

NameDescriptionTypeDefault
minLower bound.WrSliderValue | undefined0
maxUpper bound.WrSliderValue | undefined100
stepStep size for keyboard and drag.number1
rangeRender two thumbs and emit [low, high].booleanfalse
disabledDisable interaction. Bound automatically from the field's disabled state when used with [formField].booleanfalse
readonlyRefuse value changes while the thumbs stay focusable and the value still submits. Bound automatically from the field's readonly state when used with [formField]. The thumbs keep their tab stop and keep announcing their value — arrow keys, Home / End and the pointer simply move nothing — which is the whole difference from disabled, where they would leave the tab order entirely. Mirrored as aria-readonly, which role slider supports.booleanfalse
showLabelRender the current value below the track.booleantrue
ariaLabelAccessible name of the thumb — the single one, or the LOWER one in range mode. Falls back to slider.label / slider.lower.string | nullnull
upperLabelAccessible name of the upper thumb in range mode. Falls back to slider.upper.string | nullnull
valueCurrent value. Bound by [formField], or two-way via [(value)]. Shape follows range: a plain number, or [low, high] in range mode.WrSliderValue0
(touch)Emitted on blur so a bound field can mark itself touched.void

CSS variables

Custom properties ngwr/slider publishes. Each default below is declared on the component's own selector, so a :root override is shadowed by it — set them on that selector, on a wrapper you scope yourself, or inline on the element. Unlike the BEM class names, these are the supported way to restyle the component.

VariableDefaultDeclared on
--wr-slider-fillvar(--wr-color-primary).wr-slider +1 variant override
--wr-slider-labelvar(--wr-color-on-surface-muted).wr-slider
--wr-slider-thumbvar(--wr-color-surface).wr-slider
--wr-slider-thumb-bordervar(--wr-color-primary).wr-slider +1 variant override
--wr-slider-thumb-size1rem.wr-slider
--wr-slider-trackvar(--wr-color-outline).wr-slider
--wr-slider-track-height0.25rem.wr-slider