Dual Range Slider with Histogram
A two-handle price slider with a live histogram that highlights the selected range — like the filters on travel and shopping sites.
<div class="rng">
<div class="rng-head"><span>Price range</span><span class="rng-out" id="out">$200 – $800</span></div>
<div class="rng-hist" id="hist"></div>
<div class="rng-track">
<div class="rng-fill" id="fill"></div>
<input type="range" id="min" min="0" max="1000" value="200" step="10" aria-label="Minimum price">
<input type="range" id="max" min="0" max="1000" value="800" step="10" aria-label="Maximum price">
</div>
</div>*{box-sizing:border-box}
.rng{width:340px;max-width:100%;background:#fff;padding:24px;border-radius:16px;box-shadow:0 12px 36px rgba(20,25,50,.1);font-family:system-ui,sans-serif}
.rng-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;font-size:14px;color:#5a627a;font-weight:600}
.rng-out{color:#1a1f36;font-weight:800}
.rng-hist{display:flex;align-items:flex-end;gap:3px;height:46px;margin-bottom:10px}
.rng-hist span{flex:1;background:#e6e8f0;border-radius:3px 3px 0 0;transition:background .2s}
.rng-hist span.active{background:linear-gradient(180deg,#ff7a18,#ff477e)}
.rng-track{position:relative;height:6px;background:#e6e8f0;border-radius:999px}
.rng-fill{position:absolute;height:100%;background:linear-gradient(90deg,#ff7a18,#ff477e);border-radius:999px}
.rng-track input{position:absolute;width:100%;top:50%;transform:translateY(-50%);-webkit-appearance:none;appearance:none;background:none;pointer-events:none;height:6px;margin:0}
.rng-track input::-webkit-slider-thumb{-webkit-appearance:none;pointer-events:all;width:22px;height:22px;border-radius:50%;background:#fff;border:3px solid #ff477e;cursor:grab;box-shadow:0 2px 8px rgba(0,0,0,.2)}
.rng-track input::-webkit-slider-thumb:active{cursor:grabbing;transform:scale(1.15)}
.rng-track input::-moz-range-thumb{pointer-events:all;width:18px;height:18px;border-radius:50%;background:#fff;border:3px solid #ff477e;cursor:grab}var min=document.getElementById('min'),max=document.getElementById('max'),fill=document.getElementById('fill'),out=document.getElementById('out'),hist=document.getElementById('hist'),M=1000,BARS=28;
var heights=[];for(var b=0;b<BARS;b++){var h=20+Math.round(70*Math.abs(Math.sin(b*0.5)*Math.cos(b*0.3)));heights.push(h);var s=document.createElement('span');s.style.height=h+'%';hist.appendChild(s)}
function upd(){
var a=Math.min(+min.value,+max.value),b=Math.max(+min.value,+max.value);
fill.style.left=(a/M*100)+'%';fill.style.right=(100-b/M*100)+'%';
out.textContent='$'+a+' – $'+b;
[].forEach.call(hist.children,function(bar,i){var pos=i/BARS*M;bar.classList.toggle('active',pos>=a&&pos<=b)});
}
min.oninput=upd;max.oninput=upd;upd();Free to use.This snippet is plain HTML, CSS and JavaScript with no dependencies. Copy any file, or download the whole thing as a single ready-to-open .html page.