Slider

A hand-drawn range slider for selecting a numeric value.

Overview

A Slider selects a numeric value from a continuous or stepped range by dragging a thumb along a track. Use Input type="number" instead when a precise typed value matters more than a quick visual adjustment.

Anatomy

A sketchy rail (a thin rectangle) with a filled portion (from the start to the thumb) and a round thumb — all three shapes computed directly from @ghds/sketch-core, sharing one measured box and seed. On React and Web Components, a real, invisible <input type="range"> spans the full track and carries every interaction (dragging, clicking the track, and native Arrow/Home/End/PageUp/ PageDown keyboard behavior) with zero custom pointer/keydown code. React Native has no such native primitive, so dragging is hand-rolled with PanResponder (built into React Native core — no new gesture-library dependency).

Variants & States

State Status Notes
Default Implemented —
Hover Implemented The filled portion and thumb darken slightly (CSS/native pseudo-states — no JS-tracked hover flag needed).
Focus Implemented A focus ring appears around the thumb.
Disabled Implemented —
Two-thumb range Not implemented Not in v1 — "range" in the ticket names a possible future dual-thumb mode, not a v1 requirement.
Vertical orientation Not implemented —
Value tooltip while dragging Not implemented A consumer wanting a live readout derives it from a controlled value.

Usage

Do

  • Use Slider for a value with a clear, visible min/max range (e.g. volume, rating, brightness).
  • Label the value being set ("Volume"), not the current reading.

Don't

  • Don't use Slider when the exact value must be typed precisely — use Input type="number" instead.
  • Don't expect a two-thumb range mode in v1 — a single thumb only.

Accessibility

Content

The label names the value being adjusted (“Volume”, “Rating”), not the current reading or an instruction.

Props API

React@ghds/react

PropTypeDefaultDescription
labelstring—Visible label, associated via Radix Label.
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
minnumber0Minimum value.
maxnumber100Maximum value.
stepnumber1Increment step.
disabledbooleanfalseDisables interaction.
...restInputHTMLAttributes—All other native input attributes pass through (e.g. onChange, aria-valuetext, name).

Web Components@ghds/web-components

PropTypeDefaultDescription
valuenumber0Reflected attribute. Mirrored to the form value.
minnumber0Minimum value.
maxnumber100Maximum value.
stepnumber1Increment step.
disabledbooleanfalseDisables interaction and form participation.
namestring—Submitted control name.
labelstring—Optional visible label, also the accessible name.

React Native@ghds/react-native

PropTypeDefaultDescription
labelstring—Visible, accessible label — required.
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
minnumber0Minimum value.
maxnumber100Maximum value.
stepnumber1Increment step.
onValueChange(value: number) => void—Fires with the next value while dragging.
disabledbooleanfalseDisables interaction.
testIDstring—Test handle for queries.

Code examples

// React — @ghds/react (real <input type="range">; read event.target.value)
import { Slider } from '@ghds/react/slider';
import { useState } from 'react';

const [volume, setVolume] = useState(30);
<Slider label="Volume" value={volume} onChange={(event) => setVolume(Number(event.target.value))} />;
<Slider label="Rating" min={0} max={10} step={1} defaultValue={7} />;
<!-- Web Components — @ghds/web-components -->
<script type="module">
  import '@ghds/web-components/slider';
</script>
<gh-slider label="Volume" value="30"></gh-slider>
<gh-slider label="Rating" min="0" max="10" step="1" value="7"></gh-slider>
// React Native — @ghds/react-native
// Drag only — no arrow-key stepping on React Native. Value arrives via onValueChange.
import { Slider } from '@ghds/react-native/slider';

<Slider label="Volume" value={volume} onValueChange={setVolume} />;

Live Demo

React and Web Components render live below. React Native can’t run in a browser without additional react-native-web wiring (not set up in this site), so its usage is shown as a code sample instead.

React @ghds/react

Web Components @ghds/web-components