Prijsfilter met twee grepen Nieuw
Prijsfilter voor een webshop met een minimum- en maximumgreep op één balk, een staafje per prijsklasse dat laat zien waar het aanbod zit, en twee invulvelden die meelopen. Het aantal producten en de knop tellen live mee. Gebouwd op twee gewone range-inputs, dus pijltjestoetsen en schermlezers werken zonder extra code; de grepen kunnen elkaar niet passeren.
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- 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'));
Meer uit formulieren & invoer
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →