@get-set/gs-range
v1.0.2
Published
Get-Set Range slider
Downloads
175
Maintainers
Readme
GSRange
A beautiful, dependency-free range slider that ships four ways from a single
codebase — a native window.GSRange factory, a jQuery plugin ($.fn.GSRange),
an HTMLElement.prototype.GSRange method, and a React <GSRange> component with
a typed imperative ref. Single value, dual-thumb range, or N-thumb multiple
modes; fill/connect, marks & ticks, tooltips, vertical + RTL orientation, full
keyboard + ARIA accessibility, light/dark/auto theming and an accent color.
Features
- Four usage modes — vanilla factory, jQuery, prototype, and React — all
sharing the same
actions/constants/helpers/types/. - Three modes —
single(number),range(two thumbs → tuple),multiple(N thumbs → array). - Fill / connect between thumbs (or from the start to a single thumb), with an animated transition.
- Marks / ticks — boolean, interval, values array, or
{value,label}[], with snapToMarks and live tick highlighting. - Tooltips —
none/hover/always, customformatfunction and four placements, with a fade + scale entrance. - Vertical orientation and RTL layout.
- Pushable thumbs with a configurable minimum gap (or plain no-cross).
- Precision via
decimals(inferred fromstep). - Keyboard — Arrow keys, PageUp/PageDown, Home/End (RTL-aware).
- Accessibility —
role="slider",aria-valuemin/max/now/text,aria-orientation, per-thumbaria-label. - Theming —
light/dark/auto(followsprefers-color-scheme) plus an accent color;sm/md/lgsizes. - Beautiful micro-interactions — thumb grow + lift on grab, ripple ring,
animated fill, tooltip fade, tick highlighting — all respecting
prefers-reduced-motion. - Callbacks —
onInput(live),onChange,onChangeCommitted. - React-only
gsxprop for scoped per-instance styles.
Installation
npm i @get-set/gs-rangePackage entry points
| Consumer | Resolves to |
| ------------------- | ------------------------------ |
| import (React/ESM) | dist/components/GSRange.js |
| require (CJS/UMD) | dist-js/bundle.js (bundled) |
| Types | dist/components/GSRange.d.ts |
The dist-js/bundle.js build attaches window.GSRange, and — when jQuery is
present — $.fn.GSRange, plus HTMLElement.prototype.GSRange.
Build
npm run build # build:js (webpack bundle) + build:react (tsc)
npm run build:js # dist-js/bundle.js (window + jQuery + prototype)
npm run build:react # dist/ ESM + .d.tsTests
npm testUsage — Native JS (window.GSRange)
The factory accepts a CSS selector string OR a DOM element as its first argument, and returns a ref with the imperative API.
<link rel="stylesheet" href="node_modules/@get-set/gs-range/styles/GSRange.css" />
<div id="volume"></div>
<script src="node_modules/@get-set/gs-range/dist-js/bundle.js"></script>
<script>
// selector string
const slider = GSRange('#volume', {
min: 0,
max: 100,
value: 40,
tooltip: 'hover',
onInput: (v) => console.log('live', v),
onChangeCommitted: (v) => console.log('committed', v)
});
// …or a DOM element
const el = document.getElementById('volume');
GSRange(el, { value: 60 });
slider.getValue(); // 40
slider.setValue(75); // clamps + snaps
slider.reset();
</script>You can also enhance an existing <input> — it is hidden and its value is
mirrored ("40" for single, "20,80" for multi).
The instance registry — window.GSRangeConfigue
Every instance registers itself under its reference (auto-generated when
omitted):
GSRange('#volume', { reference: 'vol' });
const ref = window.GSRangeConfigue.instance('vol');
ref.setValue(90);Usage — jQuery ($.fn.GSRange)
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="node_modules/@get-set/gs-range/dist-js/bundle.js"></script>
<script>
$('.slider').GSRange({ mode: 'range', value: [20, 80], tooltip: 'always' });
</script>The adapter iterates the jQuery set and calls the factory with each element (this is why the factory must accept an element, not only a selector).
Usage — Prototype (HTMLElement.prototype.GSRange)
<script src="node_modules/@get-set/gs-range/dist-js/bundle.js"></script>
<script>
document.getElementById('price').GSRange({ min: 0, max: 1000, step: 50 });
</script>Usage — React (<GSRange>)
import { useRef } from 'react';
import GSRange, { GSRangeHandle } from '@get-set/gs-range';
import '@get-set/gs-range/styles/GSRange.css';
function Filters() {
const ref = useRef<GSRangeHandle>(null);
return (
<>
<GSRange
ref={ref}
mode="range"
min={0}
max={100}
step={5}
defaultValue={[20, 80]}
marks={[
{ value: 0, label: '0%' },
{ value: 50, label: '50%' },
{ value: 100, label: '100%' }
]}
tooltip="hover"
pushable
minGap={10}
onChange={(v) => console.log(v)}
/>
<button onClick={() => ref.current?.reset()}>Reset</button>
</>
);
}Controlled mode: pass value (+ onChange). Uncontrolled: pass
defaultValue.
The imperative ref — GSRangeHandle
| Method | Description |
| -------------------------- | ---------------------------------------------- |
| getValue() | Current value (number / tuple / array). |
| setValue(value) | Set + clamp + snap; fires the callbacks. |
| reset() | Restore the initial value. |
| destroy() | Remove scoped styles + registry entry. |
The gsx prop (React only)
Scoped, per-instance styles injected as a <style data-key> and removed on
unmount:
<GSRange
gsx={{
'.gs-range-thumb': { boxShadow: '0 2px 8px rgba(0,0,0,.4)' },
'.gs-range-connect': { background: 'linear-gradient(90deg,#f00,#00f)' }
}}
/>Options
Every option is available in all four modes (React exposes them as props).
| Option | Type | Default | Description |
| ------------------- | ------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------- |
| reference | string | auto GUID | Registry key / React instance id. |
| min | number | 0 | Lowest selectable value. |
| max | number | 100 | Highest selectable value. |
| step | number | 1 | Snap increment (0 = continuous). |
| mode | 'single' \| 'range' \| 'multiple' | 'single' | Number of thumbs / value shape. |
| value | number \| [number,number] \| number[] | see below | Current value (controlled in React). |
| defaultValue | same as value | see below | Uncontrolled initial value. |
| connect | boolean | true | Render the fill between thumbs / from start. |
| marks | boolean \| number \| number[] \| {value,label}[] | false | Tick marks. true = every step; number = interval. |
| snapToMarks | boolean | false | Snap the thumb to the nearest mark. |
| tooltip | 'none' \| 'hover' \| 'always' | 'hover' | Tooltip visibility. |
| tooltipFormat | (value, index) => string | String | Tooltip / aria value formatter. |
| tooltipPlacement | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | Tooltip position relative to the thumb. |
| vertical | boolean | false | Vertical orientation (bottom = min). |
| rtl | boolean | false | Right-to-left (horizontal only). |
| disabled | boolean | false | Block interaction + dim. |
| readOnly | boolean | false | No change, but not dimmed. |
| pushable | boolean | false | Push neighbours instead of crossing. |
| minGap | number | 0 | Minimum gap kept between adjacent thumbs. |
| decimals | number | from step | Decimal places to round + display. |
| keyboardStep | number | step | Arrow-key increment. |
| pageStep | number | step * 10 | PageUp/PageDown increment. |
| theme | 'light' \| 'dark' \| 'auto' | 'auto' | Color theme (auto = OS preference). |
| accentColor | string | #2563eb | Accent color (--gsr-accent). |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Component size preset. |
| customClass | { root, track, connect, thumb, tooltip, marks, mark } | — | Per-part class overrides. |
| className | string | — | Extra class on the root. |
| reducedMotion | 'auto' \| boolean | 'auto' | Honor prefers-reduced-motion. |
| ariaLabel | string | — | aria-label applied to every thumb. |
| ariaLabels | string[] | — | Per-thumb aria-label (indexed). |
| gsx | NestedCSS | — | React only — scoped per-instance styles. |
| onInput | (value, index) => void | — | Fired live on every drag move / keystroke. |
| onChange | (value, index) => void | — | Fired when the value changes. |
| onChangeCommitted | (value, index) => void | — | Fired once interaction ends (pointer up / keyboard). |
Default value: min (single), [min, max] (range), evenly spread (multiple).
Callback index is the thumb index, or -1 for programmatic changes.
Variant catalogs
mode (3)
| Value | Value shape | Thumbs |
| ------------ | -------------------- | ------ |
| single | number | 1 |
| range | [number, number] | 2 |
| multiple | number[] | N |
tooltip (3)
| Value | Behaviour |
| -------- | ------------------------------------------------ |
| none | No tooltip. |
| hover | Fades in on hover / focus / grab. |
| always | Permanently visible. |
tooltipPlacement (4)
top · bottom · left · right
size (3)
| Value | Track | Thumb | Font |
| ----- | ----- | ----- | ----- |
| sm | 4px | 14px | 11px |
| md | 6px | 18px | 12px |
| lg | 9px | 24px | 13px |
theme (3)
light · dark · auto (follows prefers-color-scheme)
marks forms
| Form | Meaning |
| ----------------------- | ---------------------------------------------- |
| false | No marks. |
| true | A mark at every step. |
| number | A mark at this interval. |
| number[] | Marks at the given values (label = value). |
| {value,label}[] | Fully custom marks with labels. |
Events / callbacks
| Callback | When |
| ------------------- | -------------------------------------------------------------- |
| onInput | Every pointer-move while dragging, and every keystroke. |
| onChange | Whenever the value actually changes. |
| onChangeCommitted | Once, when the interaction ends (pointer up / key / setValue). |
Methods (imperative API)
Native ref (returned by the factory / window.GSRangeConfigue.instance):
| Method | Description |
| -------------------- | ---------------------------------------- |
| getValue() | Current value in the mode shape. |
| setValue(value) | Set + clamp + snap; fires callbacks. |
| reset() | Restore the initial value. |
| setDisabled(on) | Enable / disable the control. |
| refresh() | Rebuild from updated params (keeps value).|
| destroy() | Tear down + restore the original element. |
React handle (GSRangeHandle): getValue · setValue · reset · destroy.
Examples
Native — price range with marks, dark theme, currency tooltip
GSRange('#price', {
mode: 'range',
min: 0,
max: 5000,
step: 50,
value: [1000, 3500],
theme: 'dark',
accentColor: '#16a34a',
marks: 25,
tooltip: 'always',
tooltipFormat: (v) => '$' + v.toLocaleString(),
pushable: true,
minGap: 250,
onChangeCommitted: ([lo, hi]) => console.log(lo, hi)
});React — multiple thumbs (uncontrolled) with a ref
const ref = useRef<GSRangeHandle>(null);
<GSRange
ref={ref}
mode="multiple"
min={0}
max={100}
defaultValue={[10, 50, 90]}
pushable
minGap={5}
tooltip="hover"
/>;
// later
ref.current?.setValue([20, 40, 60]);React — controlled single slider
const [v, setV] = useState(40);
<GSRange value={v} onChange={(next) => setV(next as number)} min={0} max={100} />;License
ISC
