Richtprijzen met tabs en niveaus New
Price list for a bike shop, garage or salon: tabs per type (city bike, e-bike, racing, kids) and Good, Better, Best columns, with item codes and fixed prices spanning the row. Tabs follow the ARIA pattern (arrows, Home, End), a search field filters rows with an empty state, and on mobile you pick one level so the table never scrolls sideways. Euro amounts with comma and tabular figures.
Rijwielhandel Van Leeuwen · Groningen
Richtprijzen werkplaats
Onderdelen en arbeid in een prijs. Klaar terwijl je wacht bij de meeste reparaties onder 30 minuten.
- Goed
- degelijk huismerk, prima voor dagelijks gebruik
- Beter
- A-merk, langer mee en lekbestendiger
- Best
- topmodel van het merk, voor veelrijders
Prijzen per 1 oktober 2026, inclusief btw. Afwijken doen we alleen na overleg.
| Art.nr | Reparatie | Goed | Beter | Best |
|---|
How to use it
- Paste the HTML where the page sections 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.
<!-- Richtprijzen met tabs en niveaus · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="fpr">
<div class="fpr__in">
<div class="fpr__side">
<p class="fpr__kick">Rijwielhandel Van Leeuwen · Groningen</p>
<h2 class="fpr__h">Richtprijzen werkplaats</h2>
<p class="fpr__lead">Onderdelen en arbeid in een prijs. Klaar terwijl je wacht bij de meeste reparaties onder 30 minuten.</p>
<dl class="fpr__lv">
<div><dt>Goed</dt><dd>degelijk huismerk, prima voor dagelijks gebruik</dd></div>
<div><dt>Beter</dt><dd>A-merk, langer mee en lekbestendiger</dd></div>
<div><dt>Best</dt><dd>topmodel van het merk, voor veelrijders</dd></div>
</dl>
<p class="fpr__note">Prijzen per 1 oktober 2026, inclusief btw. Afwijken doen we alleen na overleg.</p>
</div>
<div class="fpr__main">
<div class="fpr__tabs" role="tablist" aria-label="Soort fiets">
<button role="tab" id="fpr-t-stad" aria-controls="fpr-panel" aria-selected="true" data-k="stad">Stadsfiets</button>
<button role="tab" id="fpr-t-ebike" aria-controls="fpr-panel" aria-selected="false" tabindex="-1" data-k="ebike">E-bike</button>
<button role="tab" id="fpr-t-race" aria-controls="fpr-panel" aria-selected="false" tabindex="-1" data-k="race">Racefiets</button>
<button role="tab" id="fpr-t-kind" aria-controls="fpr-panel" aria-selected="false" tabindex="-1" data-k="kind">Kinderfiets</button>
</div>
<div class="fpr__bar">
<label class="fpr__search"><svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="8.5" cy="8.5" r="5.5"/><path d="M13 13l4 4"/></svg><span class="fpr__sr">Zoek een reparatie</span><input type="search" placeholder="Zoek, bv. ketting of band"></label>
<div class="fpr__lvsel" role="radiogroup" aria-label="Toon niveau"><label><input type="radio" name="fpr-lv" value="1" checked><span>Goed</span></label><label><input type="radio" name="fpr-lv" value="2"><span>Beter</span></label><label><input type="radio" name="fpr-lv" value="3"><span>Best</span></label></div>
</div>
<div id="fpr-panel" class="fpr__panel" role="tabpanel" aria-labelledby="fpr-t-stad" tabindex="0">
<table class="fpr__t" data-lv="1"><thead><tr><th scope="col">Art.nr</th><th scope="col">Reparatie</th><th scope="col" class="fpr__c1">Goed</th><th scope="col" class="fpr__c2">Beter</th><th scope="col" class="fpr__c3">Best</th></tr></thead><tbody></tbody></table>
<p class="fpr__empty" hidden></p>
</div>
</div>
</div>
</div>
</div>/* Richtprijzen met tabs en niveaus · NedDev · eigen werk. */
/* fonts (Fontshare): khand@500,600,700 + general-sans@400,500,600 */
.fpr{--fpr-green:#134e3a;--fpr-green2:#1b6650;--fpr-cream:#f7f3ea;--fpr-y:#f2c230;--fpr-ink:#14201b;--fpr-mut:#56625c;--fpr-line:#e3ddcf;background:var(--fpr-cream);color:var(--fpr-ink);font-family:'General Sans',sans-serif;box-sizing:border-box}
.fpr *,.fpr *::before,.fpr *::after{box-sizing:border-box}
.fpr button:focus-visible,.fpr input:focus-visible,.fpr__panel:focus-visible{outline:2px solid var(--fpr-green);outline-offset:2px}
.fpr__in{max-width:1200px;margin:0 auto;padding:44px 32px;display:grid;grid-template-columns:300px 1fr;gap:48px}
.fpr__kick{margin:0 0 10px;font-size:13px;font-weight:500;color:var(--fpr-mut)}
.fpr__h{font-family:'Khand',sans-serif;font-weight:700;font-size:clamp(38px,4.4vw,56px);line-height:.92;text-transform:uppercase;margin:0 0 14px;color:var(--fpr-green)}
.fpr__lead{margin:0 0 20px;font-size:15px;line-height:1.55;color:var(--fpr-mut)}
.fpr__lv{margin:0 0 18px;display:grid;gap:0}
.fpr__lv div{display:grid;grid-template-columns:62px 1fr;gap:10px;padding:9px 0;border-top:1px solid var(--fpr-line);font-size:14px}
.fpr__lv dt{font-family:'Khand',sans-serif;font-weight:600;font-size:18px;text-transform:uppercase;line-height:1.1}
.fpr__lv dd{margin:0;color:var(--fpr-mut);line-height:1.4}
.fpr__note{margin:0;font-size:12.5px;color:var(--fpr-mut)}
.fpr__main{min-width:0;background:#fff;border:1px solid var(--fpr-line);border-radius:4px}
.fpr__tabs{display:flex;border-bottom:1px solid var(--fpr-line);overflow-x:auto;scrollbar-width:none}
.fpr__tabs::-webkit-scrollbar{display:none}
.fpr__tabs button{position:relative;flex:none;padding:14px 20px;border:0;background:none;font:600 15px 'General Sans',sans-serif;color:var(--fpr-mut);cursor:pointer;white-space:nowrap;transition:color .16s,background-color .16s}
.fpr__tabs button:hover{color:var(--fpr-ink);background:var(--fpr-cream)}
.fpr__tabs button[aria-selected=true]{color:var(--fpr-green)}
.fpr__tabs button[aria-selected=true]::after{content:"";position:absolute;left:14px;right:14px;bottom:-1px;height:3px;background:var(--fpr-y)}
.fpr__bar{display:flex;gap:12px;align-items:center;padding:12px 16px;border-bottom:1px solid var(--fpr-line)}
.fpr__search{flex:1;display:flex;align-items:center;gap:8px;max-width:340px;height:40px;padding:0 12px;border:1.5px solid var(--fpr-line);border-radius:4px;background:var(--fpr-cream);transition:border-color .16s}
.fpr__search:focus-within{border-color:var(--fpr-green)}
.fpr__search svg{width:16px;height:16px;flex:none;fill:none;stroke:var(--fpr-mut);stroke-width:1.8;stroke-linecap:round}
.fpr__search input{flex:1;min-width:0;border:0;background:none;font:500 15px 'General Sans',sans-serif;color:var(--fpr-ink);outline:none}
.fpr__search input:focus-visible{outline:none}
.fpr__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.fpr__lvsel{display:none;gap:4px}
.fpr__lvsel label{position:relative}
.fpr__lvsel input{position:absolute;opacity:0}
.fpr__lvsel span{display:block;padding:7px 11px;border-radius:4px;font-size:13px;font-weight:600;border:1.5px solid var(--fpr-line);cursor:pointer}
.fpr__lvsel input:checked+span{background:var(--fpr-green);border-color:var(--fpr-green);color:#fff}
.fpr__lvsel input:focus-visible+span{outline:2px solid var(--fpr-green);outline-offset:2px}
.fpr__panel{padding:4px 16px 14px}
.fpr__t{width:100%;border-collapse:collapse;font-size:14.5px}
.fpr__t th{font-family:'Khand',sans-serif;font-weight:600;font-size:16px;text-transform:uppercase;text-align:left;padding:10px 8px;color:var(--fpr-mut);border-bottom:2px solid var(--fpr-ink)}
.fpr__t th.fpr__c1,.fpr__t th.fpr__c2,.fpr__t th.fpr__c3,.fpr__t td.fpr__p{text-align:right;width:84px}
.fpr__t td{padding:9px 8px;border-bottom:1px solid var(--fpr-line);vertical-align:top}
.fpr__t tr:not(.fpr__grp) td:first-child{font-size:12.5px;color:var(--fpr-mut);font-variant-numeric:tabular-nums;width:72px;white-space:nowrap}
.fpr__t td.fpr__p{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}
.fpr__t td.fpr__fix{text-align:center;font-variant-numeric:tabular-nums;font-weight:600;color:var(--fpr-ink);background:linear-gradient(90deg,transparent,rgba(242,194,48,.12),transparent)}
.fpr__t td.fpr__fix small{font-weight:400;color:var(--fpr-mut);margin-left:6px;font-size:12px}
.fpr__t tr.fpr__grp td{padding:16px 8px 6px;font-family:'Khand',sans-serif;font-weight:700;font-size:17px;text-transform:uppercase;color:var(--fpr-green);border-bottom:1px solid var(--fpr-ink)}
.fpr__t tbody tr:not(.fpr__grp):hover td{background:var(--fpr-cream)}
.fpr__t mark{background:rgba(242,194,48,.45);color:inherit;border-radius:2px}
.fpr__empty{margin:18px 0 8px;padding:16px;background:var(--fpr-cream);border-radius:4px;font-size:14.5px;line-height:1.5}
.fpr__empty a{color:var(--fpr-green);font-weight:600}
@media (max-width:960px){.fpr__in{grid-template-columns:1fr;gap:24px;padding:28px 16px}.fpr__side{max-width:560px}}
@media (max-width:620px){.fpr__lvsel{display:flex}.fpr__bar{flex-wrap:wrap;padding:12px}.fpr__search{max-width:none;flex:1 1 100%}.fpr__panel{padding:4px 8px 12px}
.fpr__t th.fpr__c1,.fpr__t th.fpr__c2,.fpr__t th.fpr__c3,.fpr__t td.fpr__p{display:none}
.fpr__t[data-lv="1"] .fpr__c1,.fpr__t[data-lv="2"] .fpr__c2,.fpr__t[data-lv="3"] .fpr__c3{display:table-cell}
.fpr__t tr:not(.fpr__grp) td:first-child,.fpr__t th:first-child{display:none}
.fpr__t td.fpr__fix{text-align:right;background:none}.fpr__t td.fpr__fix small{display:none}}
@media (prefers-reduced-motion:reduce){.fpr *{transition:none!important}}// Richtprijzen met tabs en niveaus · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.fpr');if(!w)return;
var P={stad:[['Onderhoud'],['SF-101','Kleine beurt: controleren, afstellen, smeren',39.5],['SF-102','Grote beurt incl. remmen en versnelling afstellen',79],['Banden'],['SF-176','Binnenband vervangen voorwiel',22.5],['SF-180','Binnenband vervangen achterwiel (naaf)',29.5],['SF-184','Binnen- en buitenband voor',44.5,54.5,64.5],['SF-188','Binnen- en buitenband achter',52.5,62.5,74.5],['Remmen en kabels'],['SF-210','Remblokken vervangen (v-brake)',24.5,29.5,34.5],['SF-214','Rollerbrake vervangen',49,59,69],['SF-350','Remkabel vervangen',19.5],['SF-352','Versnellingskabel vervangen',22.5],['Aandrijving'],['SF-410','Ketting vervangen',29.5,39.5,49.5],['SF-414','Ketting en tandwiel achter',54,69,89]],
ebike:[['Onderhoud'],['EB-101','Onderhoudsbeurt incl. software-update en accutest',99],['EB-102','Grote beurt incl. remmen ontluchten',149],['EB-120','Accu-diagnose met uitdraai',35],['Banden'],['EB-184','Buitenband voor',54.5,69.5,84.5],['EB-188','Buitenband achter (naafmotor)',69.5,84.5,99.5],['Remmen'],['EB-210','Remblokken hydraulisch, per wiel',39.5,49.5,59.5],['EB-220','Remschijf vervangen',44.5,59.5,74.5],['Aandrijving'],['EB-410','Ketting e-bike',39.5,54.5,69.5],['EB-430','Middenmotor: tandwiel voor vervangen',64.5,79.5,94.5]],
race:[['Onderhoud'],['RF-101','Afstelbeurt',59],['RF-102','Grote beurt incl. nieuw stuurlint',129],['Banden'],['RF-184','Buitenband (vouwband)',49,64,79],['RF-190','Tubeless omzetten per wiel',39.5],['Stuur en remmen'],['RF-310','Stuurlint vervangen',34.5,44.5,59.5],['RF-320','Schijfremblokken per wiel',34.5,44.5,54.5],['Aandrijving'],['RF-410','Ketting 11/12-speed',49,64,89],['RF-414','Ketting en cassette',109,149,219]],
kind:[['Onderhoud'],['KF-101','Kleine beurt',29.5],['KF-130','Zijwieltjes monteren',12.5],['Banden'],['KF-176','Binnenband vervangen',19.5],['KF-184','Binnen- en buitenband',34.5,42.5,52.5],['Remmen'],['KF-210','Remblokken vervangen',19.5,24.5,29.5],['KF-214','Terugtraprem afstellen',17.5]]};
var tabs=[].slice.call(w.querySelectorAll('[role=tab]')),panel=w.querySelector('.fpr__panel'),tb=w.querySelector('tbody'),q=w.querySelector('.fpr__search input'),emp=w.querySelector('.fpr__empty'),tbl=w.querySelector('.fpr__t'),cur='stad';
function eur(n){return '€ '+(n%1?n.toFixed(2).replace('.',','):n);}
function esc(s){return s.replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c];});}
function hl(t,s){if(!s)return t;var i=t.toLowerCase().indexOf(s);return i<0?t:t.slice(0,i)+'<mark>'+t.slice(i,i+s.length)+'</mark>'+t.slice(i+s.length);}
function paint(){var s=q.value.trim().toLowerCase(),rows=[],grp=null,n=0;
P[cur].forEach(function(r){if(r.length===1){grp=r[0];return;}
if(s&&r[1].toLowerCase().indexOf(s)<0&&r[0].toLowerCase().indexOf(s)<0)return;
if(grp){rows.push('<tr class="fpr__grp"><td colspan="5">'+grp+'</td></tr>');grp=null;}n++;
rows.push('<tr><td>'+r[0]+'</td><td>'+hl(r[1],s)+'</td>'+(r.length===3?'<td class="fpr__fix fpr__p fpr__c1 fpr__c2 fpr__c3" colspan="3">'+eur(r[2])+'<small>vaste prijs</small></td>':'<td class="fpr__p fpr__c1">'+eur(r[2])+'</td><td class="fpr__p fpr__c2">'+eur(r[3])+'</td><td class="fpr__p fpr__c3">'+eur(r[4])+'</td>')+'</tr>');});
tb.innerHTML=rows.join('');tbl.hidden=!n;emp.hidden=!!n;
if(!n)emp.innerHTML='Geen richtprijs voor <b>'+esc(q.value.trim())+'</b> bij '+w.querySelector('[aria-selected=true]').textContent.toLowerCase()+'. Bel de werkplaats, dan krijg je een prijs op maat: <a href="tel:+31503112640">050 311 26 40</a>.';}
function sel(t,focus){tabs.forEach(function(x){var on=x===t;x.setAttribute('aria-selected',on?'true':'false');x.tabIndex=on?0:-1;});panel.setAttribute('aria-labelledby',t.id);cur=t.getAttribute('data-k');paint();if(focus)t.focus();}
tabs.forEach(function(t,i){t.addEventListener('click',function(){sel(t);});t.addEventListener('keydown',function(e){var j=null;if(e.key==='ArrowRight')j=(i+1)%tabs.length;if(e.key==='ArrowLeft')j=(i-1+tabs.length)%tabs.length;if(e.key==='Home')j=0;if(e.key==='End')j=tabs.length-1;if(j!==null){e.preventDefault();sel(tabs[j],true);}});});
q.addEventListener('input',paint);
w.addEventListener('change',function(e){if(e.target.name==='fpr-lv')tbl.setAttribute('data-lv',e.target.value);});
paint();
}
init(document.querySelector('.jouw-container'));
More page sections
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 →