Prijsfilter met twee grepen New
Price filter for a web shop with a minimum and maximum handle on one track, a bar per price band that shows where the stock sits, and two input fields that follow along. The product count and the button update live. Built on two native range inputs, so arrow keys and screen readers work without extra code; the handles cannot pass each other.
How to use it
- Paste the HTML where the forms & inputs should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Prijsfilter met twee grepen · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="pds"><div class="pds__in">
<fieldset class="pds__f">
<legend class="pds__lg">Prijs</legend>
<div class="pds__hist" aria-hidden="true"></div>
<div class="pds__rng">
<div class="pds__track" aria-hidden="true"><i class="pds__fill"></i></div>
<input class="pds__r pds__r--min" type="range" min="0" max="3000" step="50" value="400" aria-label="Minimumprijs">
<input class="pds__r pds__r--max" type="range" min="0" max="3000" step="50" value="1800" aria-label="Maximumprijs">
</div>
<div class="pds__nums">
<label class="pds__lab"><span>Van</span><span class="pds__box"><span aria-hidden="true">€</span><input class="pds__n pds__n--min" type="text" inputmode="numeric" value="400" aria-label="Minimumprijs in euro"></span></label>
<label class="pds__lab"><span>Tot</span><span class="pds__box"><span aria-hidden="true">€</span><input class="pds__n pds__n--max" type="text" inputmode="numeric" value="1800" aria-label="Maximumprijs in euro"></span></label>
</div>
</fieldset>
<div class="pds__foot"><p class="pds__out"></p><button class="pds__btn" type="button">Toon fietsen</button></div>
<p class="pds__sr" aria-live="polite"></p>
</div></div>
</div>/* Prijsfilter met twee grepen · NedDev · eigen werk. */
.pds{position:absolute;inset:0;overflow:auto;display:flex;padding:14px;box-sizing:border-box;background:#f4f3f1;font-family:'Switzer',sans-serif;color:#0a0a0a}
.pds *,.pds *::before,.pds *::after{box-sizing:border-box}
.pds__in{margin:auto;width:100%;max-width:400px;background:#fff;border:1px solid rgba(10,10,10,.12);border-radius:8px;padding:14px 16px}
.pds__f{border:0;margin:0;padding:0;min-width:0}
.pds__lg{padding:0;font-size:15px;font-weight:700;margin-bottom:8px}
.pds__hist{display:flex;align-items:flex-end;gap:2px;height:38px;margin:0 11px}
.pds__hist i{flex:1;min-height:3px;background:#d9d6d0;border-radius:1px 1px 0 0;transition:background-color .15s}
.pds__hist i.is-in{background:#0a0a0a}
.pds__rng{position:relative;height:28px}
.pds__track{position:absolute;left:11px;right:11px;top:12px;height:4px;background:#d9d6d0;border-radius:2px}
.pds__fill{position:absolute;top:0;bottom:0;background:#F5480F;border-radius:2px}
.pds__r{position:absolute;left:0;top:0;width:100%;height:28px;margin:0;padding:0;background:none;-webkit-appearance:none;appearance:none;pointer-events:none;outline:none}
.pds__r::-webkit-slider-runnable-track{background:none;height:28px;border:0}
.pds__r::-webkit-slider-thumb{-webkit-appearance:none;pointer-events:auto;width:22px;height:22px;margin-top:3px;border-radius:50%;background:#fff;border:2px solid #0a0a0a;cursor:grab;transition:box-shadow .15s,transform .15s}
.pds__r::-moz-range-track{background:none;border:0}
.pds__r::-moz-range-thumb{pointer-events:auto;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid #0a0a0a;cursor:grab}
.pds__r:hover::-webkit-slider-thumb{transform:scale(1.08)}
.pds__r:active::-webkit-slider-thumb{cursor:grabbing}
.pds__r:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px rgba(245,72,15,.55)}
.pds__r:focus-visible::-moz-range-thumb{box-shadow:0 0 0 3px rgba(245,72,15,.55)}
.pds__nums{display:flex;gap:10px;margin-top:8px}
.pds__lab{flex:1;display:flex;align-items:center;gap:8px;font-size:13px;color:#4a4a4a}
.pds__box{flex:1;display:flex;align-items:center;gap:4px;border:1px solid #8c8c8c;border-radius:4px;padding:0 8px;height:34px;color:#0a0a0a;transition:border-color .15s,box-shadow .15s}
.pds__box:hover{border-color:#0a0a0a}
.pds__box:focus-within{border-color:#0a0a0a;box-shadow:0 0 0 3px rgba(245,72,15,.35)}
.pds__n{width:100%;min-width:0;height:32px;border:0;outline:0;background:none;font:500 14px 'Switzer',sans-serif;color:#0a0a0a;padding:0}
.pds__foot{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px}
.pds__out{margin:0;font-size:13px;line-height:1.35;color:#4a4a4a}
.pds__out b{color:#0a0a0a}
.pds__btn{flex:none;font:600 13.5px 'Switzer',sans-serif;padding:10px 14px;border-radius:4px;border:0;background:#0a0a0a;color:#fff;cursor:pointer;transition:background-color .15s}
.pds__btn:hover{background:#2a2a2a}
.pds__btn:active{transform:translateY(1px)}
.pds__btn:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.pds__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;margin:0}
@media (prefers-reduced-motion:reduce){.pds *{transition:none!important}}// Prijsfilter met twee grepen · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.pds');if(!w)return;
var lo=w.querySelector('.pds__r--min'),hi=w.querySelector('.pds__r--max'),nlo=w.querySelector('.pds__n--min'),nhi=w.querySelector('.pds__n--max'),fill=w.querySelector('.pds__fill'),hist=w.querySelector('.pds__hist'),out=w.querySelector('.pds__out'),btn=w.querySelector('.pds__btn'),sr=w.querySelector('.pds__sr');
var MAX=3000,GAP=100,seed=11,P=[],BINS=28,cnt=[],bars=[],i,tm;
function rnd(){seed=(seed*9301+49297)%233280;return seed/233280;}
for(i=0;i<160;i++){var v=rnd();P.push(Math.round((v*v*2700+220)/10)*10);}
for(i=0;i<BINS;i++)cnt.push(0);
P.forEach(function(p){cnt[Math.min(BINS-1,Math.floor(p/MAX*BINS))]++;});
var mx=Math.max.apply(null,cnt);
cnt.forEach(function(c){var b=document.createElement('i');b.style.height=Math.max(8,c/mx*100)+'%';hist.appendChild(b);bars.push(b);});
function eur(n){return '\u20ac\u00a0'+n.toLocaleString('nl-NL');}
function upd(src){var a=+lo.value,b=+hi.value;
if(b<GAP){b=GAP;hi.value=b;}
if(a>b-GAP){if(src===lo||src===nlo){a=b-GAP;lo.value=a;}else{b=Math.min(MAX,a+GAP);hi.value=b;a=Math.min(a,b-GAP);lo.value=a;}}
fill.style.left=(a/MAX*100)+'%';fill.style.right=(100-b/MAX*100)+'%';
lo.style.zIndex=a>MAX*.85?3:1;hi.style.zIndex=2;
if(src!==nlo)nlo.value=a;if(src!==nhi)nhi.value=b;
lo.setAttribute('aria-valuetext',eur(a));hi.setAttribute('aria-valuetext',b>=MAX?eur(b)+' of meer':eur(b));
bars.forEach(function(el,k){var c=(k+.5)/BINS*MAX;el.classList.toggle('is-in',c>=a&&c<=b);});
var n=P.filter(function(p){return p>=a&&(b>=MAX||p<=b);}).length;
var t=n===1?'fiets':'fietsen',top=b>=MAX?eur(b)+' en meer':eur(b);
out.innerHTML='<b>'+n+'</b> '+t+' van '+eur(a)+' tot '+top;
btn.textContent=n?'Toon '+n+' '+t:'Geen fietsen';btn.disabled=!n;
clearTimeout(tm);tm=setTimeout(function(){sr.textContent=n+' '+t+' gevonden tussen '+eur(a)+' en '+top;},500);}
function num(inp,rng){var v=parseInt(String(inp.value).replace(/\D/g,''),10);if(isNaN(v))v=+rng.value;v=Math.max(0,Math.min(MAX,Math.round(v/50)*50));rng.value=v;upd(inp);inp.value=rng.value;}
lo.addEventListener('input',function(){upd(lo);});hi.addEventListener('input',function(){upd(hi);});
nlo.addEventListener('change',function(){num(nlo,lo);});nhi.addEventListener('change',function(){num(nhi,hi);});
[nlo,nhi].forEach(function(inp){inp.addEventListener('keydown',function(e){if(e.key==='Enter'){e.preventDefault();inp.dispatchEvent(new Event('change'));}});});
btn.addEventListener('click',function(){sr.textContent='Filter toegepast: '+out.textContent;});
upd(null);
}
init(document.querySelector('.jouw-container'));
More forms & inputs
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →