A draggable split-ratio slider for React. Two labeled sides, spring snap, momentum, hash marks, dynamic caption. No dependencies.
npm install split-slider'use client'
import 'split-slider/styles.css'
import { SplitSlider } from 'split-slider'
export default function Demo() {
return (
<SplitSlider
left="Design"
right="Code"
defaultValue={0.6}
onValueChange={(v) => console.log(v)}
/>
)
}const [ratio, setRatio] = useState(0.5)
<SplitSlider
left="Design"
right="Code"
value={ratio}
onValueChange={setRatio}
/>formatCaption returns the text shown below the slider, recomputed as the value changes. The caption cross-fades between values.
<SplitSlider
left="Design"
right="Code"
defaultValue={0.6}
formatCaption={(v) => {
const pct = Math.round(v * 100)
if (pct <= 15) return 'Pure engineer'
if (pct <= 30) return 'Engineer-forward'
if (pct <= 45) return 'Code-leaning'
if (pct <= 55) return 'Design engineer'
if (pct <= 70) return 'Design-leaning'
if (pct <= 85) return 'Art director'
return 'Pure designer'
}}
/><SplitSlider
left="Light"
right="Dark"
defaultValue={0.4}
formatValue={(v) => v.toFixed(2)}
/>- Drag — pointer or touch on the track moves the divider
- Snap — on release, the value snaps to the nearest
stepusing an overdamped spring (no overshoot) - Momentum — drag velocity carries into the snap; pass
momentum={false}to disable - Keyboard — focusable; arrow keys step by
step, Shift+arrow doubles - Hash marks — appear during drag at every
stepinterval, hidden behind labels and the moving split
| Prop | Type | Default |
|---|---|---|
left |
string |
required |
right |
string |
required |
value |
number |
— |
defaultValue |
number |
0.5 |
onValueChange |
(value: number) => void |
— |
onValueCommit |
(value: number) => void |
— |
step |
number |
0.05 |
min |
number |
0.1 |
max |
number |
0.9 |
title |
string |
— |
formatCaption |
(value: number) => string |
— |
formatValue |
(value: number) => string |
v => Math.round(v * 100) + '%' |
momentum |
boolean |
true |
disabled |
boolean |
false |
className |
string |
— |
aria-label |
string |
`${left} to ${right} ratio` |
Default styles ship in split-slider/styles.css. The component uses scoped CSS variables under .split-slider-wrap so theming is local.
| Variable | Default (light) | Default (dark) |
|---|---|---|
--split-slider-primary |
#000000 |
#e2e2e2 |
--split-slider-subtle |
#f4f5f5 |
#242424 |
--split-slider-handle |
#888888 |
#888888 |
--split-slider-body |
rgba(0,0,0,0.85) |
rgba(255,255,255,0.70) |
--split-slider-muted |
rgba(0,0,0,0.60) |
rgba(255,255,255,0.50) |
Override per instance:
.my-slider {
--split-slider-primary: #4f46e5;
--split-slider-handle: #ffffff;
}<SplitSlider className="my-slider" left="Design" right="Code" />role="slider"witharia-valuemin,aria-valuemax,aria-valuenow(in percent)- Keyboard navigable with arrow keys
aria-labeldefaults to`${left} to ${right} ratio`; override via thearia-labelprop- Selection is suppressed during drag to prevent text-highlight bleed onto surrounding content
MIT © Ezekiel Adewumi