@mshafiqyajid/react-range
Headless range hook and styled component. Single-thumb and dual-thumb mode, snap-point tick marks, drag/always/never tooltip, inverted fill, label / hint / error / required, full keyboard navigation, ARIA-compliant.
Playground #
Props
TSX
import { RangeStyled } from "@mshafiqyajid/react-range/styled";
import "@mshafiqyajid/react-range/styles.css";
<RangeStyled
value={value}
onChange={setValue}
/>Tone variants β single slider
primary
success
warning
danger
neutral
Marks showcase
Step marks (step=25)
Labelled marks
Install #
npm install @mshafiqyajid/react-range Quick start #
import { RangeStyled } from "@mshafiqyajid/react-range/styled";
import "@mshafiqyajid/react-range/styles.css";
// Single slider
const [volume, setVolume] = useState(40);
<RangeStyled mode="single" value={volume} onChange={setVolume} tone="primary" label="Volume" />
// Range slider
const [range, setRange] = useState<[number, number]>([20, 80]);
<RangeStyled mode="range" value={range} onChange={setRange} tone="primary" label="Price range" /> Marks #
Pass marks={true} to derive ticks from step, or an array of { value, label? } objects for custom positions and labels.
// Auto-marks from step
<RangeStyled mode="single" min={0} max={100} step={25} marks />
// Custom labelled marks
<RangeStyled
mode="range"
marks={[
{ value: 0, label: "Low" },
{ value: 50, label: "Mid" },
{ value: 100, label: "High" },
]}
/> Tooltip #
Control tooltip visibility with showTooltip. Use tooltipFormat to customise the displayed value.
// Show only while dragging (default)
<RangeStyled mode="single" showTooltip="drag" />
// Always visible
<RangeStyled mode="single" showTooltip="always" tooltipFormat={(v) => `$${v}`} />
// Never show
<RangeStyled mode="range" showTooltip="never" /> Form field #
Combine label, hint, error, required, and onChangeEnd for a proper form control.
<RangeStyled
mode="range"
label="Budget"
hint="Set your minimum and maximum"
required
value={range}
onChange={setRange}
onChangeEnd={handleSubmit}
/>
// Error state
<RangeStyled
mode="range"
label="Price"
error="Range must be at least $10 apart"
value={range}
onChange={setRange}
/> Inverted #
Set inverted to reverse the fill direction β useful for "remaining capacity" or reversed value semantics.
<RangeStyled mode="single" inverted value={value} onChange={setValue} /> Headless #
import { useRange } from "@mshafiqyajid/react-range";
const { value, rootProps, trackProps, getThumbProps, getTrackFillProps } = useRange({
defaultValue: [20, 80],
min: 0,
max: 100,
mode: "range",
onChange: (v) => console.log(v),
onChangeEnd: (v) => console.log("committed:", v),
});
return (
<div {...rootProps} className="my-range">
<div {...trackProps} className="track">
<div className="rail" />
<div {...getTrackFillProps()} className="fill" />
{[0, 1].map((i) => (
<div key={i} {...getThumbProps(i)} className="thumb" />
))}
</div>
</div>
); API #
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | [number, number] | β | Controlled value |
| defaultValue | number | [number, number] | min / [min, max] | Uncontrolled initial value |
| onChange | (v) => void | β | Fires on every change |
| onChangeEnd | (v) => void | β | Fires on pointer release or keyboard commit |
| min | number | 0 | Minimum value |
| max | number | 100 | Maximum value |
| step | number | 1 | Step increment |
| mode | "single" | "range" | "range" | Single or dual thumb |
| disabled | boolean | false | Disable interaction |
| inverted | boolean | false | Invert fill direction |
| showTooltip | "always" | "drag" | "never" | "drag" | Tooltip visibility |
| tooltipFormat | (v: number) => string | β | Format tooltip value |
| marks | boolean | { value, label? }[] | false | Tick marks; true derives from step |
| size | "sm" | "md" | "lg" | "md" | Track and thumb size |
| tone | "neutral" | "primary" | "success" | "warning" | "danger" | "primary" | Fill color |
| label | string | β | Label above the slider |
| hint | string | β | Helper text below |
| error | string | β | Error text β sets data-invalid and danger tone |
| required | boolean | β | Mark as required |
| invalid | boolean | β | Force invalid state without error text |
| className | string | β | Extra class on root div |
| style | CSSProperties | β | Inline style on root div |
Keyboard #
| Key | Action |
|---|---|
| ArrowRight / ArrowUp | +1 step |
| ArrowLeft / ArrowDown | -1 step |
| Shift + Arrow | Β±10% of range |
| Home | Jump to minimum |
| End | Jump to maximum |