How to Create a Price Range Slider Using Vanilla JavaScript

on in JavaScript DOM, JavaScript Sliders
Last modified on

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;
}

Related posts