JSFiddle - React, Tailwind, and code Playground
by Eric
HTML
<div>
<input id="a" type="range" min="0" max="10" value="0"/>
<input id="b" type="range" min="11" max="20" value="20" />
</div>
<output></output>
SCSS
body {
min-height: 100px; // just to hold open the fiddle when embedded
}
div {
display: flex;
}
// This just gets the basics. To customize: https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/
input {
flex: 1 0 0;
min-width: 0; // they can be 0 size
margin: 0;
padding: 0;
}
input::-webkit-slider-thumb {
margin: 0;
padding: 0;
}
output {
display: block;
text-align: center;
margin-top: 3px;
color: gray;
}
JavaScript
console.clear(); // on fiddle run
// On an event of kind, for els, call fn
const on = (...kinds) => (...els) => (fn) =>
kinds.forEach(kind =>
els.forEach(el => el.addEventListener(kind, fn))
)
const a = document.getElementById('a');
const b = document.getElementById('b');
const o = document.querySelector('output');
on('input', 'mousedown')(a, b)(update);
// 'mousedown' because otherwise you can "lock" the other slider in place at min=max=value
const max = 20;
const min = 0;
const range = max - min + 1; // +1 inclusive
update(); // 1x
// As the user drags on input, update the available range and visual space for both inputs
function update({target} = {}) {
let pivot; // unless otherwise acted on
if (target === a) {
if (a.valueAsNumber >= Number(a.max)) {
pivot = Math.min(max - 1, Number(a.max) + 1);
}
}
if (target === b) {
if (b.valueAsNumber <= Number(b.min)) {
pivot = Math.max(min, Number(b.min) - 2);
}
}
if (pivot != null) {
a.max = pivot;
b.min = pivot + 1;
}
a.style.flexGrow = stepsIn(a);
b.style.flexGrow = stepsIn(b);
// Print selected range
o.innerText = `${a.value} - ${b.value}`;
}
// Number of discrete steps in an input range
function stepsIn(el) {
return Number(el.max) - Number(el.min) + 1;
}