Adres via postcode en huisnummer Nieuw
Nederlands adresformulier: postcode (validatie 1234 AB, wordt netjes opgemaakt) plus huisnummer en toevoeging vult straat en plaats automatisch in. Staten: leeg, ongeldige postcode, zoeken (spinner), gevonden (adreskaart), toevoeging verplicht (keuzelijst met de bestaande toevoegingen), niet gevonden (dan zelf invullen) en handmatig aanpassen. De demo gebruikt een lijstje nep-adressen; in productie koppel je de PDOK Locatieserver (gratis, BAG-data, /free?fq=postcode:...&fq=huisnummer:...).
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.
<!-- Adres via postcode en huisnummer · NedDev · eigen werk. -->
<div class="jouw-container">
<form class="bap" novalidate><p class="bap__h">Waar mogen we bezorgen?</p><div class="bap__row"><div class="bap__f bap__f--pc"><label for="bap-pc">Postcode</label><input id="bap-pc" class="bap__pc" autocomplete="postal-code" placeholder="1234 AB" maxlength="7" aria-describedby="bap-msg" spellcheck="false"></div><div class="bap__f bap__f--nr"><label for="bap-nr">Huisnummer</label><input id="bap-nr" class="bap__nr" inputmode="numeric" autocomplete="off" maxlength="5" aria-describedby="bap-msg"></div><div class="bap__f bap__f--tv"><label for="bap-tv">Toevoeging</label><input id="bap-tv" class="bap__tv" autocomplete="off" maxlength="4" placeholder="optioneel"><select id="bap-tvs" class="bap__tvs" hidden aria-label="Toevoeging"></select></div></div><div class="bap__out" aria-live="polite"><p class="bap__msg" id="bap-msg"></p><div class="bap__card" hidden><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M8 14.5s5-4.6 5-8.5A5 5 0 0 0 3 6c0 3.9 5 8.5 5 8.5z"/><circle cx="8" cy="6" r="1.8"/></svg><p class="bap__adr"></p><button type="button" class="bap__edit">Wijzigen</button></div><div class="bap__man" hidden><div class="bap__f"><label for="bap-str">Straat</label><input id="bap-str" class="bap__str" autocomplete="address-line1"></div><div class="bap__f"><label for="bap-pl">Plaats</label><input id="bap-pl" class="bap__pl" autocomplete="address-level2"></div></div></div><p class="bap__try">Probeer <button type="button" data-a="3011 AD|12">3011 AD 12</button><button type="button" data-a="2511 CV|5">2511 CV 5</button><button type="button" data-a="1234 AB|1">1234 AB 1</button><button type="button" data-a="0123 AB|4">0123 AB</button></p></form>
</div>/* Adres via postcode en huisnummer · NedDev · eigen werk. */
.bap{position:absolute;inset:0;margin:0;padding:12px 16px;background:#fff;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;overflow:auto;display:flex;flex-direction:column;gap:8px;container-type:inline-size}
.bap__h{margin:0;font-size:14px;font-weight:700}
.bap__row{display:grid;grid-template-columns:1.25fr 1fr .9fr;gap:8px}
.bap__f{min-width:0}
.bap__f label{display:block;margin-bottom:3px;font-size:11.5px;font-weight:600}
.bap__f input,.bap__f select{display:block;width:100%;box-sizing:border-box;height:36px;padding:0 10px;border:1px solid rgba(10,10,10,.3);border-radius:4px;background:#fff;font:500 14px 'Switzer',system-ui,sans-serif;color:#0a0a0a;font-variant-numeric:tabular-nums;transition:border-color .15s,box-shadow .15s}
.bap__f input::placeholder{color:#8a8781}
.bap__f input:hover,.bap__f select:hover{border-color:rgba(10,10,10,.55)}
.bap__f input:focus,.bap__f select:focus{outline:none;border-color:#0a0a0a;box-shadow:0 0 0 3px rgba(245,72,15,.3)}
.bap__f input[aria-invalid="true"],.bap__f select[aria-invalid="true"]{border-color:#c4231b;background:#fffafa}
.bap__pc{text-transform:uppercase;letter-spacing:.03em}
.bap__tvs[hidden],.bap__tv[hidden]{display:none}
.bap__out{min-height:46px}
.bap__msg{margin:0;font-size:12px;line-height:1.4;color:#5c5a56;display:flex;align-items:center;gap:7px}
.bap__msg:empty{display:none}
.bap.is-err .bap__msg{color:#c4231b}
.bap.is-warn .bap__msg{color:#8a4b00}
.bap.is-busy .bap__msg::before{content:'';flex:none;width:12px;height:12px;border:2px solid #0a0a0a;border-right-color:transparent;border-radius:50%;animation:bap-spin .7s linear infinite}
@keyframes bap-spin{to{transform:rotate(360deg)}}
.bap__card{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:4px;background:#eaf4ed;color:#14532d}
.bap__card[hidden]{display:none}
.bap__adr{flex:1;margin:0;font-size:13.5px;line-height:1.35;color:#0a0a0a}
.bap__adr b{font-weight:700}
.bap__edit{border:0;background:none;padding:2px 4px;font:600 12px 'Switzer',system-ui,sans-serif;color:#14532d;text-decoration:underline;text-underline-offset:2px;cursor:pointer;border-radius:3px}
.bap__edit:hover{background:#d5eadb}
.bap__edit:focus-visible{outline:2px solid #14532d;outline-offset:1px}
.bap__man{display:grid;grid-template-columns:1.4fr 1fr;gap:8px;margin-top:6px}
.bap__man[hidden]{display:none}
.bap__try{margin:auto 0 0;display:flex;flex-wrap:wrap;align-items:center;gap:4px;font:500 10px 'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:.06em;color:#5c5a56}
.bap__try button{padding:2px 6px;border:1px dashed rgba(10,10,10,.3);border-radius:3px;background:none;font:600 10.5px 'JetBrains Mono',monospace;color:#0a0a0a;cursor:pointer;transition:border-color .15s,background-color .15s}
.bap__try button:hover{border-style:solid;border-color:#0a0a0a;background:#f4f3f1}
.bap__try button:focus-visible{outline:2px solid #0a0a0a;outline-offset:1px}
@container (max-width:340px){.bap__row{grid-template-columns:1fr 1fr}.bap__f--pc{grid-column:1/-1}}
@media (prefers-reduced-motion:reduce){.bap *{transition:none!important}.bap.is-busy .bap__msg::before{animation-duration:2s}}// Adres via postcode en huisnummer · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var f=root.querySelector('.bap');if(!f)return;
var pc=f.querySelector('.bap__pc'),nr=f.querySelector('.bap__nr'),tv=f.querySelector('.bap__tv'),tvs=f.querySelector('.bap__tvs'),msg=f.querySelector('.bap__msg'),card=f.querySelector('.bap__card'),adr=f.querySelector('.bap__adr'),man=f.querySelector('.bap__man'),str=f.querySelector('.bap__str'),pl=f.querySelector('.bap__pl');
/* nep-adressen. Productie: fetch('https://api.pdok.nl/bzk/locatieserver/search/v3_1/free?fq=postcode:'+pc+'&fq=huisnummer:'+nr+'&fl=straatnaam,woonplaatsnaam,huisletter,huisnummertoevoeging') */
var DB={'3011AD':{s:'Hoogstraat',p:'Rotterdam',n:{10:[],12:['A','B','C'],14:[]}},'2511CV':{s:'Spui',p:'Den Haag',n:{3:[],5:[],7:['1','2']}},'1017CT':{s:'Prinsengracht',p:'Amsterdam',n:{263:[],267:['H','1','2','3']}},'9711LM':{s:'Grote Markt',p:'Groningen',n:{1:[],2:[]}},'5611EM':{s:'Stratumseind',p:'Eindhoven',n:{32:[],34:['A']}}};
var RE=/^[1-9][0-9]{3} ?(?!SA|SD|SS)[A-Z]{2}$/,timer=null,found=null;
function state(s,t){f.classList.remove('is-err','is-warn','is-busy');if(s)f.classList.add('is-'+s);msg.textContent=t||''}
function invalid(el,on){if(on)el.setAttribute('aria-invalid','true');else el.removeAttribute('aria-invalid')}
function norm(v){return v.toUpperCase().replace(/\s+/g,'')}
function reset(){card.hidden=true;man.hidden=true;found=null;tvs.hidden=true;tv.hidden=false;tvs.removeAttribute('aria-invalid')}
function showCard(){var add=tvs.hidden?tv.value.trim().toUpperCase():tvs.value;adr.innerHTML='<b>'+found.s+' '+nr.value.trim()+(add?' '+add:'')+'</b><br>'+pc.value+' '+found.p;card.hidden=false;str.value=found.s;pl.value=found.p}
function lookup(fromBlur){clearTimeout(timer);reset();var p=norm(pc.value),n=nr.value.trim();invalid(pc,false);invalid(nr,false);
if(!p&&!n){state('','');return}
if(p.length>=6||fromBlur){if(!RE.test(p.slice(0,4)+' '+p.slice(4))){invalid(pc,true);state('err',/^0/.test(p)?'Een postcode begint niet met een 0.':'Gebruik vier cijfers en twee letters, zoals 2511 CV.');return}pc.value=p.slice(0,4)+' '+p.slice(4)}
else{state('','');return}
if(!n){state('','Vul je huisnummer in, dan zoeken we het adres op.');return}
if(!/^[0-9]+$/.test(n)){invalid(nr,true);state('err','Alleen cijfers bij huisnummer. Een letter vul je in bij toevoeging.');return}
state('busy','Adres zoeken');
timer=setTimeout(function(){var rec=DB[p];
if(!rec||!(n in rec.n)){state('warn','We vinden dit adres niet. Controleer het nummer of vul straat en plaats zelf in.');man.hidden=false;str.value='';pl.value=rec?rec.p:'';return}
found=rec;var opts=rec.n[n];
if(opts.length){tv.hidden=true;tvs.hidden=false;tvs.innerHTML='<option value="">Kies</option>'+opts.map(function(o){return '<option>'+o+'</option>'}).join('');tvs.setAttribute('aria-invalid','true');state('warn','Op dit nummer zijn meerdere adressen. Kies je toevoeging.');tvs.focus();return}
state('','');showCard()},450)}
pc.addEventListener('input',function(){if(norm(pc.value).length>=6)lookup(false);else{clearTimeout(timer);reset();invalid(pc,false);if(f.classList.contains('is-err'))state('','')}});
pc.addEventListener('blur',function(){if(pc.value.trim())lookup(true)});
nr.addEventListener('input',function(){clearTimeout(timer);timer=setTimeout(function(){lookup(false)},350)});
tv.addEventListener('input',function(){if(found)showCard()});
tvs.addEventListener('change',function(){if(tvs.value){tvs.removeAttribute('aria-invalid');state('','');showCard()}else{card.hidden=true;state('warn','Kies je toevoeging.')}});
f.querySelector('.bap__edit').addEventListener('click',function(){card.hidden=true;man.hidden=false;state('','Pas straat en plaats aan als ze niet kloppen.');str.focus()});
f.addEventListener('submit',function(e){e.preventDefault()});
f.querySelector('.bap__try').addEventListener('click',function(e){var b=e.target.closest('button[data-a]');if(!b)return;var a=b.dataset.a.split('|');pc.value=a[0];nr.value=a[1];tv.value='';lookup(true)});
pc.value='3011 AD';nr.value='14';lookup(true);
}
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 →