Range slider

Sets an ordered numeric interval with two named native range controls and visible endpoint values.

Budget
€120
€420

A useful interval

Project search

Set the lower and upper budget. Neither endpoint can cross the other.

Budget
€120
€420

Use it for

  • A numeric lower and upper bound such as budget or duration.
  • Separate labeled tracks when each endpoint needs clear keyboard and touch access.

Not for

  • A single setting; use Slider.
  • Time-based seeking with buffered media; use MediaScrubber.

Three ways in. They share one source, so the pixels match whichever you pick.

1. Import the package

npm install @noorddev/vlak-react

// once, next to your app's root
import "@noorddev/vlak-react/css";

import { RangeSlider } from "@noorddev/vlak-react";

Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/range-slider.

2. Vendor the source

npx @noorddev/vlak-cli add range-slider

The StyleX leaf lands in components/vlak/ with its dependencies, for your own compiler to own. See StyleX.

3. Through shadcn

npx shadcn add https://vlak.dev/r/range-slider.json

The same registry item, installed by shadcn's CLI.

CSS only

<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />

No React. Link vlak.css and use the markup and classes below.

import { RangeSlider } from "@noorddev/vlak-react";

<RangeSlider label="Budget" name="budget" defaultValue={[120, 420]} min={0} max={800} step={20} formatValue={(value) => `€${value}`} />

RangeSlider

PropTypeDefaultDescription
value[number, number]
defaultValue[number, number]
onValueChange(value: [number, number]) => void
minnumber0
maxnumber100
stepnumber1
labelReactNode"Range"
lowerLabelstring"From"
upperLabelstring"To"
namestring
disabledboolean
formatValue(value: number) => stringString

Also accepts Omit<HTMLAttributes<HTMLFieldSetElement>, "onChange" | "defaultValue">.

KeysDoes
TabMoves between the lower and upper native range inputs.
Arrow keys, Home, EndUses the browser's native range stepping within the other endpoint's bounds.
<fieldset class="rs-range-slider"><legend class="rs-range-slider-legend">Budget</legend><div class="rs-range-slider-row"><label class="rs-range-slider-label" for="budget-from">From</label><input class="rs-range-slider-input" id="budget-from" type="range" min="0" max="800" value="120" /><output class="rs-range-slider-output" for="budget-from">120</output></div><div class="rs-range-slider-row"><label class="rs-range-slider-label" for="budget-to">To</label><input class="rs-range-slider-input" id="budget-to" type="range" min="120" max="800" value="420" /><output class="rs-range-slider-output" for="budget-to">420</output></div></fieldset>
.rs-range-slider.rs-range-slider-legend.rs-range-slider-row.rs-range-slider-label.rs-range-slider-input.rs-range-slider-output