Keuzehulp warmtepomp New
Heat pump selector with four questions on choice cards, a progress bar, Next enabled only after a choice and an explained recommendation based on the answers. Uses View Transitions between questions (fallback: instant swap). A strong lead magnet for installers.
Keuzehulp · Warmtepomp
Vraag 1 van 4
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.
<!-- Keuzehulp warmtepomp · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="kzh"><div class="kzh__in">
<div class="kzh__top"><p class="kzh__eye">Keuzehulp · Warmtepomp</p><p class="kzh__n">Vraag 1 van 4</p></div>
<div class="kzh__bar" role="progressbar" aria-label="Voortgang keuzehulp" aria-valuemin="0" aria-valuemax="4" aria-valuenow="0"><i></i></div>
<form class="kzh__q" novalidate>
<fieldset class="kzh__fs"></fieldset>
<div class="kzh__act"><button type="button" class="kzh__back">Terug</button><span class="kzh__hint" id="kzh-hint">Kies een antwoord</span><button type="submit" class="kzh__next" disabled aria-describedby="kzh-hint">Volgende</button></div>
</form>
<div class="kzh__res" tabindex="-1" hidden></div>
<p class="kzh__sr" aria-live="polite"></p>
</div></div>
</div>/* Keuzehulp warmtepomp · NedDev · eigen werk. */
.kzh [hidden]{display:none!important}
.kzh{position:absolute;inset:0;overflow:auto;display:flex;padding:14px;box-sizing:border-box;background:#f4f3f1;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;container-type:inline-size;scrollbar-width:thin}
.kzh *,.kzh *::before,.kzh *::after{box-sizing:border-box}
.kzh__in{margin:auto;width:100%;max-width:640px}
.kzh__top{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.kzh__eye,.kzh__n{margin:0;font:500 10.5px 'JetBrains Mono',monospace;letter-spacing:.08em;text-transform:uppercase;color:#5a5a5a}
.kzh__n{color:#0a0a0a}
.kzh__bar{height:4px;background:#e2dfda;border-radius:2px;margin:8px 0 12px;overflow:hidden}
.kzh__bar i{display:block;height:100%;width:0;background:#F5480F;transition:width .35s cubic-bezier(.2,.8,.2,1)}
.kzh__fs{border:0;margin:0;padding:0;min-width:0}
.kzh__h{font-size:17px;font-weight:700;letter-spacing:-.01em;padding:0;margin:0 0 10px}
.kzh__opts{display:grid;gap:8px;grid-template-columns:1fr}
@container (min-width:380px){.kzh__opts{grid-template-columns:1fr 1fr}}
@container (min-width:600px){.kzh__opts--3{grid-template-columns:repeat(3,1fr)}}
.kzh__opt{position:relative;display:flex;align-items:center;gap:10px;background:#fff;border:1px solid rgba(10,10,10,.18);border-radius:6px;padding:10px 12px;cursor:pointer;transition:border-color .15s,box-shadow .15s}
.kzh__opt:hover{border-color:#0a0a0a}
.kzh__opt input{position:absolute;opacity:0;width:1px;height:1px}
.kzh__ot{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.kzh__ot b{font-size:14px;font-weight:600}
.kzh__ot small{font-size:12px;color:#5a5a5a;line-height:1.35}
.kzh__dot{flex:none;width:16px;height:16px;border-radius:50%;border:1.5px solid #8c8c8c;background:#fff;transition:border-color .15s,box-shadow .15s}
.kzh__opt:has(input:checked){border-color:#0a0a0a;box-shadow:inset 0 0 0 1px #0a0a0a}
.kzh__opt:has(input:checked) .kzh__dot{border-color:#0a0a0a;box-shadow:inset 0 0 0 4px #fff;background:#F5480F}
.kzh__opt:has(input:focus-visible){outline:2px solid #F5480F;outline-offset:2px}
.kzh__lv{flex:none;display:flex;gap:2px;align-items:flex-end;height:14px}
.kzh__lv span{width:4px;border-radius:1px;background:#d6d3ce}
.kzh__lv span:nth-child(1){height:6px}.kzh__lv span:nth-child(2){height:10px}.kzh__lv span:nth-child(3){height:14px}
.kzh__lv span.on{background:#0a0a0a}
.kzh__act{display:flex;align-items:center;gap:10px;margin-top:12px}
.kzh__hint{margin-left:auto;font-size:12px;color:#5a5a5a}
.kzh__back,.kzh__next,.kzh__cta,.kzh__again{font:600 13.5px 'Switzer',system-ui,sans-serif;border-radius:4px;padding:9px 16px;cursor:pointer;transition:background .15s,color .15s,border-color .15s}
.kzh__back,.kzh__again{background:#fff;border:1px solid #8c8c8c;color:#0a0a0a}
.kzh__back:hover,.kzh__again:hover{border-color:#0a0a0a}
.kzh__next,.kzh__cta{background:#0a0a0a;border:1px solid #0a0a0a;color:#fff}
.kzh__next:hover:not(:disabled),.kzh__cta:hover{background:#F5480F;border-color:#F5480F;color:#0a0a0a}
.kzh__next:disabled{background:#e4e2de;border-color:#e4e2de;color:#5a5a5a;cursor:not-allowed}
.kzh__back:focus-visible,.kzh__next:focus-visible,.kzh__cta:focus-visible,.kzh__again:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.kzh__res{background:#fff;border:1px solid rgba(10,10,10,.14);border-radius:6px;padding:14px 16px}
.kzh__res:focus{outline:none}
.kzh__badge{display:inline-block;font:600 10px 'JetBrains Mono',monospace;letter-spacing:.08em;text-transform:uppercase;background:#F5480F;color:#0a0a0a;border-radius:100px;padding:3px 8px}
.kzh__rt{margin:6px 0 2px;font-size:19px;font-weight:700;letter-spacing:-.015em;line-height:1.15}
.kzh__price{margin:0 0 8px;font-size:13px;color:#3d3d3d}
.kzh__why{margin:0 0 8px;padding:0;list-style:none;display:grid;gap:5px}
.kzh__why li{position:relative;padding-left:18px;font-size:13px;line-height:1.45}
.kzh__why li::before{content:'';position:absolute;left:2px;top:5px;width:8px;height:4px;border:2px solid #146C43;border-top:0;border-right:0;transform:rotate(-45deg)}
.kzh__also{margin:0 0 10px;font-size:12.5px;color:#5a5a5a}
.kzh__ra{display:flex;flex-wrap:wrap;gap:8px}
.kzh__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;margin:0}
::view-transition-old(kzh-q),::view-transition-new(kzh-q){animation-duration:.22s}
@media (prefers-reduced-motion:reduce){.kzh *{transition:none!important;animation:none!important}}// Keuzehulp warmtepomp · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root=root.querySelector('.kzh')||root;
var uid=Math.random().toString(36).slice(2,7);
root.querySelectorAll('[id]').forEach(function(el){var o=el.id,n=o+'-'+uid;el.id=n;root.querySelectorAll('[aria-describedby="'+o+'"]').forEach(function(x){x.setAttribute('aria-describedby',n);});});
var Q=[{h:'Wat voor woning heb je?',o:[['app','Appartement','Buitenunit op balkon of dak'],['tus','Tussenwoning','Buren aan twee kanten'],['hoek','Hoekwoning of 2-onder-1-kap','Eén vrije zijgevel'],['vrij','Vrijstaand','Ruimte rondom het huis']]},
{h:'Hoe goed is je huis geïsoleerd?',lv:[3,2,1],o:[['goed','Goed','Label A of B, overal dubbel glas'],['redelijk','Redelijk','Label C of D, deels na-geïsoleerd'],['matig','Matig of weet ik niet','Label E of lager, oud glas']]},
{h:'Hoe verwarm je je huis nu?',o:[['vloer','Vloerverwarming','In het hele huis of beneden'],['lt','Nieuwe radiatoren','Lage temperatuur of convectoren'],['rad','Gewone radiatoren','Cv-ketel op 60 tot 80 graden']]},
{h:'Wat vind je het belangrijkst?',o:[['prijs','Lage aanschafprijs','Snel besparen met een kleine investering'],['gas','Helemaal van het gas af','Geen gasaansluiting meer nodig'],['maand','Laagste kosten op termijn','Hogere investering, lagere energierekening']]}];
var form=root.querySelector('.kzh__q'),fs=root.querySelector('.kzh__fs'),n=root.querySelector('.kzh__n'),bar=root.querySelector('.kzh__bar'),fill=bar.querySelector('i'),back=root.querySelector('.kzh__back'),next=root.querySelector('.kzh__next'),hint=root.querySelector('.kzh__hint'),res=root.querySelector('.kzh__res'),sr=root.querySelector('.kzh__sr');
var ans=[],cur=0,reduce=matchMedia('(prefers-reduced-motion: reduce)').matches;
function esc(s){return String(s).replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c];});}
function progress(v){fill.style.width=(v/Q.length*100)+'%';bar.setAttribute('aria-valuenow',v);}
function render(i,focus){cur=i;var q=Q[i];n.textContent='Vraag '+(i+1)+' van '+Q.length;progress(i);
fs.innerHTML='<legend class="kzh__h">'+esc(q.h)+'</legend><div class="kzh__opts'+(q.o.length===3?' kzh__opts--3':'')+'">'+q.o.map(function(o,j){return '<label class="kzh__opt"><input type="radio" name="kzh-'+uid+'" value="'+o[0]+'"'+(ans[i]===o[0]?' checked':'')+'><span class="kzh__dot" aria-hidden="true"></span><span class="kzh__ot"><b>'+esc(o[1])+'</b><small>'+esc(o[2])+'</small></span>'+(q.lv?'<span class="kzh__lv" aria-hidden="true">'+[1,2,3].map(function(k){return '<span'+(k<=q.lv[j]?' class="on"':'')+'></span>';}).join('')+'</span>':'')+'</label>';}).join('')+'</div>';
back.style.visibility=i?'visible':'hidden';next.textContent=i===Q.length-1?'Toon mijn advies':'Volgende';state();
if(focus){var f=fs.querySelector('input:checked')||fs.querySelector('input');f.focus({preventScroll:true});}}
function state(){next.disabled=!ans[cur];hint.textContent=ans[cur]?'':'Kies een antwoord';}
function swap(fn){if(document.startViewTransition&&!reduce){form.style.viewTransitionName='kzh-q';res.style.viewTransitionName='kzh-q';try{var t=document.startViewTransition(fn);t.finished.then(clear,clear);return;}catch(_){}}fn();clear();}
function clear(){form.style.viewTransitionName='';res.style.viewTransitionName='';}
form.addEventListener('change',function(e){if(e.target.type==='radio'){ans[cur]=e.target.value;state();}});
back.addEventListener('click',function(){if(cur)swap(function(){render(cur-1,true);});});
form.addEventListener('submit',function(e){e.preventDefault();if(!ans[cur])return;if(cur<Q.length-1)swap(function(){render(cur+1,true);});else swap(advies);});
var TYPES={hyb:['Hybride warmtepomp','Indicatie € 3.500 tot € 6.000 inclusief installatie, vóór ISDE-subsidie.'],lw:['Volledig elektrische lucht-water-warmtepomp','Indicatie € 9.000 tot € 15.000 inclusief installatie, vóór ISDE-subsidie.'],bodem:['Bodemwarmtepomp','Indicatie € 15.000 tot € 25.000 inclusief bron, vóór ISDE-subsidie.']};
function advies(){var w=ans[0],iso=ans[1],afg=ans[2],wens=ans[3];
var sc=(iso==='goed'?2:iso==='redelijk'?1:0)+(afg==='vloer'?2:afg==='lt'?1:0)+(wens==='gas'?2:wens==='maand'?1:0);
var t=sc>=4?((w==='vrij'&&wens==='maand')?'bodem':'lw'):'hyb',alt=t==='hyb'?'lw':'hyb',why=[];
if(iso==='matig')why.push('Je huis verliest nog veel warmte. Op koude dagen springt de cv-ketel bij, zo blijft het warm.');
if(iso==='goed')why.push('Je huis is goed geïsoleerd, dus een warmtepomp kan het hele jaar alleen verwarmen.');
if(afg==='vloer')why.push('Vloerverwarming werkt op lage temperatuur, precies waar een warmtepomp zuinig op draait.');
if(afg==='rad')why.push('Gewone radiatoren vragen hoge temperaturen; een hybride vangt dat op zonder nieuwe radiatoren.');
if(afg==='lt')why.push('Je nieuwe radiatoren kunnen met lager water verwarmen, dat scheelt stroom.');
if(w==='app')why.push('In een appartement heb je meestal toestemming van de VvE nodig voor de buitenunit.');
if(t==='bodem')why.push('Met ruimte rond het huis is een bodembron mogelijk: stil en de laagste maandlasten.');
if(t==='hyb'&&wens==='gas')why.push('Wil je van het gas af? Isoleer eerst; daarna vervang je de hybride door een volledig elektrische.');
if(t==='hyb'&&wens==='prijs')why.push('De laagste instapprijs, en je bespaart vaak al de helft op je gasverbruik.');
progress(Q.length);n.textContent='Jouw advies';form.hidden=true;res.hidden=false;
res.innerHTML='<span class="kzh__badge">Past het best</span><h3 class="kzh__rt">'+TYPES[t][0]+'</h3><p class="kzh__price">'+TYPES[t][1]+'</p><ul class="kzh__why">'+why.slice(0,3).map(function(x){return '<li>'+esc(x)+'</li>';}).join('')+'</ul><p class="kzh__also">Ook bekijken: '+TYPES[alt][0].toLowerCase()+'.</p><div class="kzh__ra"><button type="button" class="kzh__cta">Plan gratis adviesgesprek</button><button type="button" class="kzh__again" data-a="edit">Antwoorden aanpassen</button><button type="button" class="kzh__again" data-a="opnieuw">Opnieuw</button></div>';
sr.textContent='Advies: '+TYPES[t][0];res.focus({preventScroll:true});}
res.addEventListener('click',function(e){var b=e.target.closest('button');if(!b)return;
if(b.classList.contains('kzh__cta')){b.textContent='Aanvraag ontvangen, we bellen je';b.disabled=true;sr.textContent='Aanvraag voor een adviesgesprek ontvangen';return;}
swap(function(){res.hidden=true;form.hidden=false;if(b.dataset.a==='opnieuw')ans=[];render(b.dataset.a==='opnieuw'?0:Q.length-1,true);});});
render(0,false);
}
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 →