Hero-zoeker: postcode, soort en straal Nieuw
Zoeker als hero voor kinderopvang, sportclub of praktijk met meerdere vestigingen: soort-chips, postcode, straal en een knop die live telt hoeveel locaties er zijn. Chips zijn echte checkboxes (Tab en Spatie werken), de teller meldt zich via aria-live; staten fout, leeg, laden en resultaat zitten erin. In productie koppel je de postcode aan de PDOK Locatieserver voor coördinaten.
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
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.
<!-- 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'));
Meer uit paginasecties
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 →