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