All JavaScript range sliders are hacks or workarounds. Because there’s no native HTML element for a range slider (only a single value slider), there are lots of libraries and solutions out there.
Mine is the simplest 🤨 and the most fit for my purpose. Feel free to borrow it and improve upon it.
Demo
See a live demo here.
HTML
I’m using an SVG for the slider handles:
<div class="range-slider">
<span>from <input type="number" value="25000" min="0" max="100000" step="500"> to <input type="number" value="75000" min="0" max="100000" step="500"></span>
<input value="25000" min="0" max="100000" step="500" type="range">
<input value="50000" min="0" max="100000" step="500" type="range">
<svg width="100%" height="24">
<line x1="4" y1="0" x2="480" y2="0" stroke="#444" stroke-width="12" stroke-dasharray="1 28"></line>
</svg>
</div>
Something to consider is changing the x2
value (480
in the example above) to whatever width you need.
JavaScript
(function() {
const parent = document.querySelector('.range-slider');
if (!parent) {
return;
}
const rangeS = parent.querySelectorAll('input[type="range"]'),
numberS = parent.querySelectorAll('input[type="number"]');
rangeS.forEach((el) => {
el.oninput = () => {
let slide1 = parseFloat(rangeS[0].value),
slide2 = parseFloat(rangeS[1].value);
if (slide1 > slide2) {
[slide1, slide2] = [slide2, slide1];
}
numberS[0].value = slide1;
numberS[1].value = slide2;
}
});
numberS.forEach((el) => {
el.oninput = () => {
let number1 = parseFloat(numberS[0].value),
number2 = parseFloat(numberS[1].value);
if (number1 > number2) {
let tmp = number1;
numberS[0].value = number2;
numberS[1].value = tmp;
}
rangeS[0].value = number1;
rangeS[1].value = number2;
}
});
})();
JavaScript (minified, just for fun)
!function(){const e=document.querySelector(".range-slider");if(!e)return;const l=e.querySelectorAll('input[type="range"]'),a=e.querySelectorAll('input[type="number"]');l.forEach(e=>{e.oninput=(()=>{let e=parseFloat(l[0].value),t=parseFloat(l[1].value);e>t&&([e,t]=[t,e]),a[0].value=e,a[1].value=t})}),a.forEach(e=>{e.oninput=(()=>{let e=parseFloat(a[0].value),t=parseFloat(a[1].value);if(e>t){let l=e;a[0].value=t,a[1].value=l}l[0].value=e,l[1].value=t})})}();
CSS
The bulk of this code is used to style the sliders, based on different browsers.
.range-slider {
width: 480px;
/* Match this to the SVG's x2 value */
margin: auto;
text-align: center;
position: relative;
height: 6em;
}
.range-slider svg,
.range-slider input[type="range"] {
position: absolute;
left: 0;
bottom: 0;
}
input[type="number"] {
border: 1px solid #ddd;
text-align: center;
font-size: 1.6em;
}
input[type="number"]:invalid,
input[type="number"]:out-of-range {
border: 2px solid #ff6347;
}
input[type="range"] {
-webkit-appearance: none;
appearance: none;
width: 100%;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]:focus::-webkit-slider-runnable-track {
background: #2497e3;
}
input[type="range"]:focus::-ms-fill-lower {
background: #2497e3;
}
input[type="range"]:focus::-ms-fill-upper {
background: #2497e3;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 5px;
cursor: pointer;
animate: 0.2s;
background: #2497e3;
border-radius: 1px;
box-shadow: none;
border: 0;
}
input[type="range"]::-webkit-slider-thumb {
z-index: 2;
position: relative;
box-shadow: 0px 0px 0px #000;
border: 1px solid #2497e3;
height: 18px;
width: 18px;
border-radius: 25px;
background: #a1d0ff;
cursor: pointer;
-webkit-appearance: none;
appearance: none;
margin-top: -7px;
}
input[type="range"]::-moz-range-track {
width: 100%;
height: 5px;
cursor: pointer;
animate: 0.2s;
background: #2497e3;
border-radius: 1px;
box-shadow: none;
border: 0;
}
input[type="range"]::-moz-range-thumb {
z-index: 2;
position: relative;
box-shadow: 0px 0px 0px #000;
border: 1px solid #2497e3;
height: 18px;
width: 18px;
border-radius: 25px;
background: #a1d0ff;
cursor: pointer;
}
input[type="range"]::-ms-track {
width: 100%;
height: 5px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
color: transparent;
}
input[type="range"]::-ms-fill-lower,
input[type="range"]::-ms-fill-upper {
background: #2497e3;
border-radius: 1px;
box-shadow: none;
border: 0;
}
input[type="range"]::-ms-thumb {
z-index: 2;
position: relative;
box-shadow: 0px 0px 0px #000;
border: 1px solid #2497e3;
height: 18px;
width: 18px;
border-radius: 25px;
background: #a1d0ff;
cursor: pointer;
}