Hero-zoeker: postcode, soort en straal New
Search-as-hero for childcare, sports clubs or multi-location practices: type chips, postcode, radius and a button that live-counts matching locations. Chips are real checkboxes (Tab and Space work), the count is announced via aria-live; error, empty, loading and result states included. In production, resolve postcodes via the PDOK Locatieserver.
Kinderopvang Klavertje · 14 locaties rond Amersfoort
Opvang dichtbij huis, met vaste gezichten op de groep
Kinderdagverblijf, peuteropvang en BSO in Amersfoort, Hoogland, Leusden en Soest. Zoek een locatie en plan een rondleiding.
Rondleiding elke woensdag en vrijdag, 9:30 of 15:00
Demo
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.
<!-- Hero-zoeker: postcode, soort en straal · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="kzo">
<div class="kzo__in">
<div class="kzo__copy">
<p class="kzo__eyebrow">Kinderopvang Klavertje · 14 locaties rond Amersfoort</p>
<h2 class="kzo__h">Opvang dichtbij huis, met vaste gezichten op de groep</h2>
<p class="kzo__lead">Kinderdagverblijf, peuteropvang en BSO in Amersfoort, Hoogland, Leusden en Soest. Zoek een locatie en plan een rondleiding.</p>
<form class="kzo__card" novalidate>
<fieldset class="kzo__set">
<legend class="kzo__lbl">Soort opvang</legend>
<div class="kzo__chips">
<label class="kzo__chip is-on"><input type="checkbox" name="kzo-soort" value="kdv" checked><span><b>Kinderdagverblijf</b><small>0 tot 4 jaar</small></span></label>
<label class="kzo__chip"><input type="checkbox" name="kzo-soort" value="po"><span><b>Peuteropvang</b><small>2 tot 4 jaar</small></span></label>
<label class="kzo__chip"><input type="checkbox" name="kzo-soort" value="bso"><span><b>BSO</b><small>4 tot 13 jaar</small></span></label>
</div>
</fieldset>
<div class="kzo__row">
<div class="kzo__field kzo__field--pc">
<label class="kzo__lbl" for="kzo-pc">Postcode</label>
<input id="kzo-pc" class="kzo__input" type="text" maxlength="7" placeholder="3811 AB" autocomplete="postal-code" spellcheck="false" aria-describedby="kzo-hint">
</div>
<div class="kzo__field kzo__field--r">
<label class="kzo__lbl" for="kzo-r">Afstand</label>
<select id="kzo-r" class="kzo__select"><option value="2">binnen 2 km</option><option value="5" selected>binnen 5 km</option><option value="10">binnen 10 km</option><option value="15">binnen 15 km</option></select>
</div>
<button class="kzo__go" type="submit"><span class="kzo__spin" aria-hidden="true"></span><span class="kzo__go-t">Toon <b class="kzo__n">9</b> locaties</span><svg class="kzo__arr" viewBox="0 0 20 20" aria-hidden="true"><path d="M4 10h11M11 5l5 5-5 5"/></svg></button>
</div>
<p id="kzo-hint" class="kzo__hint">Probeer 3811, 3828 of 3768.</p>
<p class="kzo__sr" aria-live="polite"></p>
<div class="kzo__res" hidden></div>
</form>
</div>
<div class="kzo__media">
<img src="https://neddev.com/lab-media/hero-zoeker-1.webp" alt="Pedagogisch medewerker speelt met twee peuters in de tuin van een kinderdagverblijf" loading="lazy">
<p class="kzo__stamp"><b>Rondleiding</b> elke woensdag en vrijdag, 9:30 of 15:00</p>
</div>
</div>
<div class="kzo__demo" aria-label="Demo-staten"><span>Demo</span><button type="button" data-kzo-demo="fout">Toon fout</button><button type="button" data-kzo-demo="leeg">Toon leeg</button><button type="button" data-kzo-demo="laden">Toon laden</button><button type="button" data-kzo-demo="ok">Toon resultaat</button></div>
</div>
</div>/* Hero-zoeker: postcode, soort en straal · NedDev · eigen werk. */
/* fonts (Fontshare): chillax@500,600 + satoshi@400,500,700 */
.kzo{--kzo-bg:#fbf5ec;--kzo-ink:#1d2a24;--kzo-green:#1f4d3a;--kzo-green2:#2c6a50;--kzo-apri:#f0a35e;--kzo-line:#e3d8c5;--kzo-mut:#55635b;--kzo-err:#a5321f;background:var(--kzo-bg);color:var(--kzo-ink);font-family:'Satoshi',sans-serif;box-sizing:border-box}
.kzo *,.kzo *::before,.kzo *::after{box-sizing:border-box}
.kzo__in{max-width:1200px;margin:0 auto;padding:48px 32px 36px;display:grid;grid-template-columns:1.08fr .92fr;gap:44px;align-items:stretch}
.kzo__eyebrow{margin:0 0 14px;font-size:13px;font-weight:700;letter-spacing:.02em;color:var(--kzo-green2)}
.kzo__h{font-family:'Chillax',sans-serif;font-weight:600;font-size:clamp(30px,3.6vw,46px);line-height:1.04;letter-spacing:-.015em;margin:0 0 14px;max-width:19ch}
.kzo__lead{font-size:16px;line-height:1.55;color:var(--kzo-mut);margin:0 0 22px;max-width:50ch}
.kzo__card{background:#fff;border:1px solid var(--kzo-line);border-radius:14px;padding:20px;box-shadow:0 18px 40px -28px rgba(31,77,58,.45)}
.kzo__set{border:0;margin:0 0 14px;padding:0;min-width:0}
.kzo__lbl{display:block;font-size:12px;font-weight:700;color:var(--kzo-mut);margin:0 0 7px;padding:0}
.kzo__chips{display:flex;flex-wrap:wrap;gap:8px}
.kzo__chip{position:relative;display:block;cursor:pointer}
.kzo__chip input{position:absolute;opacity:0;width:1px;height:1px;margin:0}
.kzo__chip span{display:flex;flex-direction:column;gap:1px;padding:9px 14px 9px 34px;border:1.5px solid var(--kzo-line);border-radius:999px;background:#fff;transition:border-color .18s,background-color .18s;position:relative}
.kzo__chip span::before{content:"";position:absolute;left:12px;top:50%;width:14px;height:14px;margin-top:-7px;border:1.5px solid #9aa79f;border-radius:4px;background:#fff center/10px no-repeat;transition:background-color .18s,border-color .18s}
.kzo__chip b{font-size:14px;font-weight:700;line-height:1.2}
.kzo__chip small{font-size:12px;color:var(--kzo-mut)}
.kzo__chip:hover span{border-color:#b9c7bd}
.kzo__chip.is-on span{border-color:var(--kzo-green);background:#eef4ef}
.kzo__chip.is-on span::before{background-color:var(--kzo-green);border-color:var(--kzo-green);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.3 2.3 4.7-5' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.kzo__chip input:focus-visible+span{outline:2px solid var(--kzo-apri);outline-offset:2px}
.kzo__row{display:grid;grid-template-columns:1fr 150px auto;gap:10px;align-items:end}
.kzo__field{min-width:0}
.kzo__input,.kzo__select{width:100%;height:50px;font:500 16px 'Satoshi',sans-serif;color:var(--kzo-ink);background:#fbf9f5;border:1.5px solid var(--kzo-line);border-radius:10px;padding:0 14px;outline:none;transition:border-color .18s,box-shadow .18s}
.kzo__input{text-transform:uppercase;letter-spacing:.06em;font-weight:700}
.kzo__input::placeholder{color:#9aa39d;font-weight:500}
.kzo__select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%231d2a24' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;background-size:12px;padding-right:32px;cursor:pointer}
.kzo__input:hover,.kzo__select:hover{border-color:#c9bda6}
.kzo__input:focus-visible,.kzo__select:focus-visible{border-color:var(--kzo-green);box-shadow:0 0 0 3px rgba(31,77,58,.16)}
.kzo__input[aria-invalid=true]{border-color:var(--kzo-err);box-shadow:0 0 0 3px rgba(165,50,31,.12)}
.kzo__go{height:50px;display:inline-flex;align-items:center;gap:10px;padding:0 18px 0 20px;border:0;border-radius:10px;background:var(--kzo-green);color:#fff;font:700 15px 'Satoshi',sans-serif;cursor:pointer;white-space:nowrap;transition:background-color .18s,transform .12s}
.kzo__go:hover{background:var(--kzo-green2)}
.kzo__go:active{transform:translateY(1px)}
.kzo__go:focus-visible{outline:2px solid var(--kzo-apri);outline-offset:3px}
.kzo__go:disabled{background:#c8cfca;color:#4b554f;cursor:not-allowed}
.kzo__n{font-variant-numeric:tabular-nums;display:inline-block;min-width:1ch}
.kzo__n.is-bump{animation:kzo-bump .32s ease}
@keyframes kzo-bump{0%{transform:translateY(-4px);opacity:.3}100%{transform:none;opacity:1}}
.kzo__arr{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:transform .18s}
.kzo__go:hover .kzo__arr{transform:translateX(3px)}
.kzo__spin{display:none;width:16px;height:16px;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:kzo-spin .7s linear infinite}
.kzo__go[aria-busy=true] .kzo__spin{display:block}
.kzo__go[aria-busy=true] .kzo__arr{display:none}
@keyframes kzo-spin{to{transform:rotate(360deg)}}
.kzo__hint{margin:9px 0 0;font-size:13px;color:var(--kzo-mut);min-height:18px}
.kzo__hint.is-err{color:var(--kzo-err);font-weight:700}
.kzo__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;margin:0}
.kzo__res{margin-top:14px;border-top:1px solid var(--kzo-line);padding-top:12px}
.kzo__res-h{display:flex;justify-content:space-between;align-items:baseline;gap:10px;font-size:13px;color:var(--kzo-mut);margin:0 0 6px}
.kzo__res-h b{color:var(--kzo-ink);font-size:14px}
.kzo__list{list-style:none;margin:0;padding:0}
.kzo__item{display:grid;grid-template-columns:1fr auto;gap:2px 12px;padding:9px 0;border-bottom:1px dashed var(--kzo-line)}
.kzo__item:last-child{border-bottom:0}
.kzo__item a{font-weight:700;color:var(--kzo-ink);text-decoration:none;font-size:15px}
.kzo__item a:hover{color:var(--kzo-green2);text-decoration:underline;text-underline-offset:3px}
.kzo__item a:focus-visible{outline:2px solid var(--kzo-apri);outline-offset:2px;border-radius:2px}
.kzo__km{font-variant-numeric:tabular-nums;font-weight:700;font-size:14px;text-align:right}
.kzo__meta{font-size:12.5px;color:var(--kzo-mut)}
.kzo__plek{font-size:12px;font-weight:700;text-align:right;color:var(--kzo-green2)}
.kzo__plek.is-wacht{color:#8a5a14}
.kzo__empty{background:#fdf3e7;border-radius:10px;padding:12px 14px;font-size:14px;line-height:1.5}
.kzo__empty button{margin-top:8px;font:700 13px 'Satoshi',sans-serif;background:none;border:1.5px solid var(--kzo-green);color:var(--kzo-green);border-radius:999px;padding:6px 12px;cursor:pointer;transition:background-color .18s,color .18s}
.kzo__empty button:hover{background:var(--kzo-green);color:#fff}
.kzo__empty button:focus-visible{outline:2px solid var(--kzo-apri);outline-offset:2px}
.kzo__media{position:relative;border-radius:18px 18px 18px 120px;overflow:hidden;min-height:420px;background:#dfe7dc}
.kzo__media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:78% center}
.kzo__stamp{position:absolute;right:16px;bottom:16px;margin:0;background:var(--kzo-apri);color:#2b1a08;font-size:13px;line-height:1.35;padding:10px 14px;border-radius:12px;max-width:220px}
.kzo__stamp b{display:block;font-family:'Chillax',sans-serif;font-size:16px}
.kzo__demo{max-width:1200px;margin:0 auto;padding:0 32px 20px;display:flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:12px;color:var(--kzo-mut)}
.kzo__demo span{font-weight:700;margin-right:4px}
.kzo__demo button{font:600 12px 'Satoshi',sans-serif;background:transparent;border:1px solid var(--kzo-line);border-radius:999px;padding:5px 11px;color:var(--kzo-ink);cursor:pointer;transition:background-color .18s}
.kzo__demo button:hover{background:#fff}
.kzo__demo button:focus-visible{outline:2px solid var(--kzo-green);outline-offset:2px}
@media (max-width:900px){.kzo__in{grid-template-columns:1fr;gap:24px;padding:28px 16px 20px}.kzo__media{min-height:220px;order:-1;border-radius:14px 14px 14px 60px}.kzo__demo{padding:0 16px 18px}}
@media (max-width:560px){.kzo__row{grid-template-columns:1fr 1fr}.kzo__go{grid-column:1/-1;justify-content:center}.kzo__chip span{padding:8px 12px 8px 32px}.kzo__card{padding:16px}}
@media (prefers-reduced-motion:reduce){.kzo *{animation:none!important;transition:none!important}}// Hero-zoeker: postcode, soort en straal · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.kzo');if(!w)return;
var L=[
{n:'De Boomgaard',wk:'Soesterkwartier',x:-1.2,y:1.0,t:['kdv','bso'],p:1},
{n:'Het Zonnehuis',wk:'Binnenstad',x:.2,y:.3,t:['kdv','po'],p:0},
{n:'Bosrand',wk:'Bergkwartier',x:-.5,y:-1.7,t:['kdv'],p:1},
{n:'Liendert',wk:'Liendert',x:2.4,y:-.2,t:['kdv','po'],p:1},
{n:'Kikkerland',wk:'Schothorst',x:3.3,y:.4,t:['kdv','po','bso'],p:0},
{n:'De Wilgen',wk:'Kattenbroek',x:5.2,y:-1.2,t:['kdv','bso'],p:1},
{n:'Speelhof',wk:'Nieuwland',x:6.2,y:1.0,t:['bso'],p:1},
{n:'De Kroonsteen',wk:'Vathorst',x:6.5,y:3.2,t:['kdv','po','bso'],p:0},
{n:'Klavertje Hoogland',wk:'Hoogland',x:1.4,y:4.6,t:['kdv','po'],p:1},
{n:'De Hooiberg',wk:'Hooglanderveen',x:5.1,y:4.7,t:['bso'],p:1},
{n:'Leusden Centrum',wk:'Leusden',x:-1.0,y:-5.8,t:['kdv','bso','po'],p:0},
{n:'Leusden Zuid',wk:'Leusden',x:-.3,y:-7.2,t:['bso'],p:1},
{n:'Overhees',wk:'Soest',x:-8.6,y:1.9,t:['kdv','po'],p:1},
{n:'Soestdijk',wk:'Soest',x:-9.6,y:3.0,t:['bso'],p:0}];
var PC={'3811':[0,0],'3812':[-1,1.2],'3813':[-1.5,-.8],'3814':[1.2,1.5],'3815':[1.8,-.6],'3816':[2.2,.8],'3817':[.5,-1.6],'3818':[-.6,-1.8],'3821':[2.5,-2],'3822':[3.4,.2],'3823':[4.2,2.4],'3824':[5,-1.5],'3825':[6.2,1.6],'3828':[1.5,4.5],'3829':[5,4.6],'3831':[-1,-6],'3832':[-1.6,-5],'3833':[-.4,-7],'3763':[-9.6,3],'3768':[-8.6,1.8],'3769':[-8,-.5]};
var form=w.querySelector('.kzo__card'),inp=w.querySelector('#kzo-pc'),sel=w.querySelector('#kzo-r'),btn=w.querySelector('.kzo__go'),
txt=w.querySelector('.kzo__go-t'),hint=w.querySelector('.kzo__hint'),live=w.querySelector('.kzo__sr'),res=w.querySelector('.kzo__res'),
chips=[].slice.call(w.querySelectorAll('.kzo__chip input'));
var HINT='Probeer 3811, 3828 of 3768.',NAMES={kdv:'KDV',po:'Peuteropvang',bso:'BSO'},last=-1,timer=0;
function pc4(v){var m=String(v).replace(/\s+/g,'').toUpperCase().match(/^(\d{4})([A-Z]{2})?$/);return m?m[1]:null;}
function km(n){return n.toFixed(1).replace('.',',');}
function calc(){
var ty=chips.filter(function(c){return c.checked;}).map(function(c){return c.value;});
var p=pc4(inp.value),r=+sel.value,out=L.filter(function(l){return l.t.some(function(t){return ty.indexOf(t)>-1;});});
var known=p&&PC[p];
if(p&&!known)return {ty:ty,p:p,list:[],outside:true};
if(known){out=out.map(function(l){return Object.assign({d:Math.hypot(l.x-known[0],l.y-known[1])},l);}).filter(function(l){return l.d<=r;}).sort(function(a,b){return a.d-b.d;});}
return {ty:ty,p:p,list:out,near:!!known};
}
function paint(){
chips.forEach(function(c){c.parentNode.classList.toggle('is-on',c.checked);});
var s=calc();
if(!s.ty.length){btn.disabled=true;txt.textContent='Kies een soort opvang';last=-1;return s;}
btn.disabled=false;
var n=s.list.length;
txt.innerHTML='Toon <b class="kzo__n">'+n+'</b> '+(n===1?'locatie':'locaties');
if(n!==last){var b=txt.querySelector('.kzo__n');void b.offsetWidth;b.classList.add('is-bump');clearTimeout(timer);timer=setTimeout(function(){live.textContent=n+(n===1?' locatie':' locaties')+' gevonden';},400);}
last=n;return s;
}
function err(m){hint.textContent=m;hint.classList.add('is-err');inp.setAttribute('aria-invalid','true');res.hidden=true;inp.focus();}
function clearErr(){hint.textContent=HINT;hint.classList.remove('is-err');inp.removeAttribute('aria-invalid');}
function render(s){
res.hidden=false;var r=+sel.value;
if(s.outside){res.innerHTML='<div class="kzo__empty"><b>'+s.p+' valt buiten ons werkgebied.</b><br>Wij zitten in Amersfoort, Hoogland, Leusden en Soest. Bel 033 204 18 60, dan denken we mee.</div>';return;}
if(!s.list.length){var nx=r<15?(r<5?5:r<10?10:15):0;res.innerHTML='<div class="kzo__empty"><b>Geen locatie binnen '+r+' km van '+s.p+'.</b>'+(nx?'<br><button type="button" data-kzo-wider="'+nx+'">Zoek binnen '+nx+' km</button>':'')+'</div>';return;}
var head='<p class="kzo__res-h"><b>'+s.list.length+(s.list.length===1?' locatie':' locaties')+(s.near?' bij '+s.p:'')+'</b><span>'+(s.near?'gesorteerd op afstand':'alle locaties')+'</span></p>';
var items=s.list.slice(0,4).map(function(l){return '<li class="kzo__item"><a href="#">'+l.n+'</a><span class="kzo__km">'+(l.d!=null?km(l.d)+' km':'')+'</span><span class="kzo__meta">'+l.wk+' · '+l.t.map(function(t){return NAMES[t];}).join(', ')+'</span><span class="kzo__plek'+(l.p?'':' is-wacht')+'">'+(l.p?'Direct plek':'Plek vanaf jan 2027')+'</span></li>';}).join('');
var more=s.list.length>4?'<li class="kzo__item"><a href="#">en nog '+(s.list.length-4)+' locaties bekijken</a></li>':'';
res.innerHTML=head+'<ul class="kzo__list">'+items+more+'</ul>';
}
function search(delay){
var v=inp.value.trim(),s=calc();
if(!v){err('Vul je postcode in, bijvoorbeeld 3811 AB.');return;}
if(!s.p){err('Een postcode heeft 4 cijfers en 2 letters, bijvoorbeeld 3811 AB.');return;}
clearErr();btn.setAttribute('aria-busy','true');btn.disabled=true;txt.textContent='Zoeken';live.textContent='Bezig met zoeken';
setTimeout(function(){btn.removeAttribute('aria-busy');paint();render(calc());live.textContent=res.textContent.slice(0,80);},delay||650);
}
form.addEventListener('submit',function(e){e.preventDefault();search();});
inp.addEventListener('input',function(){if(inp.getAttribute('aria-invalid'))clearErr();paint();});
sel.addEventListener('change',paint);
chips.forEach(function(c){c.addEventListener('change',paint);});
res.addEventListener('click',function(e){var b=e.target.closest('[data-kzo-wider]');if(!b)return;sel.value=b.getAttribute('data-kzo-wider');paint();search(400);});
w.querySelector('.kzo__demo').addEventListener('click',function(e){var b=e.target.closest('[data-kzo-demo]');if(!b)return;var k=b.getAttribute('data-kzo-demo');
function set(pc,r,ty){inp.value=pc;sel.value=r;chips.forEach(function(c){c.checked=ty.indexOf(c.value)>-1;});paint();}
if(k==='fout'){set('38A1',5,['kdv']);search();}
if(k==='leeg'){set('3829 KL',2,['po']);search();}
if(k==='laden'){set('3811 AB',5,['kdv','bso']);search(2600);}
if(k==='ok'){set('3811 AB',5,['kdv','po']);search();}
});
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 →