Meerstaps intake met concept Nieuw
Intakeformulier in vier stappen met een zijbalk die afgeronde, actieve en komende stappen toont, voortgangsbalk, tekenteller, terug zonder dataverlies, controlestap met Wijzig-knoppen en "Opslaan voor later" in localStorage (met try/catch en een nette melding als opslaan niet mag). Container queries zetten de zijbalk op smalle schermen om in een stappenrij.
Intake ontvangen
We bellen je binnen 1 werkdag om een eerste afspraak te plannen.
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.
<!-- Meerstaps intake met concept · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="msi"><div class="msi__in">
<div class="msi__restore" role="status" hidden><span class="msi__restore-t"></span><button type="button" class="msi__wis">Wis concept</button></div>
<div class="msi__card">
<aside class="msi__side">
<p class="msi__brand">Fysio Lindenhof · Utrecht</p>
<ol class="msi__steps">
<li><button type="button" class="msi__st" data-go="0"><span class="msi__st-n">1</span><span class="msi__st-t">Klacht</span></button></li>
<li><button type="button" class="msi__st" data-go="1"><span class="msi__st-n">2</span><span class="msi__st-t">Gegevens</span></button></li>
<li><button type="button" class="msi__st" data-go="2"><span class="msi__st-n">3</span><span class="msi__st-t">Verzekering</span></button></li>
<li><button type="button" class="msi__st" data-go="3"><span class="msi__st-n">4</span><span class="msi__st-t">Controle</span></button></li>
</ol>
<div class="msi__bar" role="progressbar" aria-label="Voortgang intake" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><i></i></div>
<p class="msi__tip">Geen verwijzing nodig. De intake duurt ongeveer 3 minuten.</p>
</aside>
<form class="msi__form" novalidate>
<p class="msi__count">Stap <b>1</b> van 4</p>
<fieldset class="msi__pane" data-p="0" tabindex="-1"><legend class="msi__h">Waar heb je last van?</legend>
<div class="msi__chips"><label class="msi__chip"><input type="radio" name="plek" value="Rug"><span>Rug</span></label><label class="msi__chip"><input type="radio" name="plek" value="Nek of schouder"><span>Nek of schouder</span></label><label class="msi__chip"><input type="radio" name="plek" value="Knie"><span>Knie</span></label><label class="msi__chip"><input type="radio" name="plek" value="Anders"><span>Anders</span></label></div>
<p class="msi__e" data-e="plek"></p>
<label class="msi__l" for="msi-klacht">Omschrijf je klacht <small>(minimaal 10 tekens)</small></label>
<textarea class="msi__i" id="msi-klacht" name="klacht" rows="2" maxlength="250" aria-describedby="msi-klacht-e msi-klacht-c"></textarea>
<div class="msi__row"><p class="msi__e" id="msi-klacht-e" data-e="klacht"></p><span class="msi__cnt" id="msi-klacht-c">0/250 tekens</span></div>
</fieldset>
<fieldset class="msi__pane" data-p="1" tabindex="-1" hidden><legend class="msi__h">Je gegevens</legend>
<label class="msi__l" for="msi-naam">Naam</label><input class="msi__i" id="msi-naam" name="naam" autocomplete="name" aria-describedby="msi-naam-e"><p class="msi__e" id="msi-naam-e" data-e="naam"></p>
<div class="msi__two"><div><label class="msi__l" for="msi-geb">Geboortedatum</label><input class="msi__i" id="msi-geb" name="geb" type="date" autocomplete="bday" aria-describedby="msi-geb-e"><p class="msi__e" id="msi-geb-e" data-e="geb"></p></div>
<div><label class="msi__l" for="msi-email">E-mailadres</label><input class="msi__i" id="msi-email" name="email" type="email" autocomplete="email" aria-describedby="msi-email-e"><p class="msi__e" id="msi-email-e" data-e="email"></p></div></div>
</fieldset>
<fieldset class="msi__pane" data-p="2" tabindex="-1" hidden><legend class="msi__h">Hoe ben je verzekerd?</legend>
<label class="msi__l" for="msi-zv">Zorgverzekeraar</label>
<select class="msi__i" id="msi-zv" name="zv" aria-describedby="msi-zv-e"><option value="">Kies je verzekeraar</option><option>Zilveren Kruis</option><option>CZ</option><option>VGZ</option><option>Menzis</option><option>DSW</option><option>ONVZ</option><option>Anders</option></select>
<p class="msi__e" id="msi-zv-e" data-e="zv"></p>
<p class="msi__l" id="msi-aanv-l">Aanvullend verzekerd voor fysiotherapie?</p>
<div class="msi__chips" role="radiogroup" aria-labelledby="msi-aanv-l"><label class="msi__chip"><input type="radio" name="aanv" value="Ja"><span>Ja</span></label><label class="msi__chip"><input type="radio" name="aanv" value="Nee"><span>Nee</span></label><label class="msi__chip"><input type="radio" name="aanv" value="Weet ik niet"><span>Weet ik niet</span></label></div>
<p class="msi__e" data-e="aanv"></p>
</fieldset>
<fieldset class="msi__pane" data-p="3" tabindex="-1" hidden><legend class="msi__h">Klopt alles?</legend><dl class="msi__dl"></dl></fieldset>
<div class="msi__act"><button type="button" class="msi__back">Terug</button><button type="button" class="msi__save">Opslaan voor later</button><button type="submit" class="msi__next"><span class="msi__spin" aria-hidden="true"></span><span class="msi__next-t">Volgende</span></button></div>
<p class="msi__live" aria-live="polite"></p>
</form>
<div class="msi__done" tabindex="-1" hidden><svg viewBox="0 0 40 40" aria-hidden="true"><circle cx="20" cy="20" r="18"/><path d="M12 20.5l5.5 5.5L28 15"/></svg><h3 class="msi__h">Intake ontvangen</h3><p>We bellen je binnen 1 werkdag om een eerste afspraak te plannen.</p><button type="button" class="msi__new">Nieuwe intake</button></div>
</div></div></div>
</div>/* Meerstaps intake met concept · NedDev · eigen werk. */
.msi [hidden]{display:none!important}
.msi{position:absolute;inset:0;overflow:auto;display:flex;padding:12px;box-sizing:border-box;background:#f4f3f1;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;container-type:inline-size;scrollbar-width:thin}
.msi *,.msi *::before,.msi *::after{box-sizing:border-box}
.msi__in{margin:auto;width:100%;max-width:760px}
.msi__restore{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:6px 12px;background:#0a0a0a;color:#fff;border-radius:4px;padding:8px 12px;margin-bottom:8px;font-size:12.5px}
.msi__wis{font:600 12px 'Switzer',system-ui,sans-serif;background:none;border:0;color:#fff;text-decoration:underline;cursor:pointer;padding:2px}
.msi__card{display:grid;grid-template-columns:1fr;background:#fff;border:1px solid rgba(10,10,10,.12);border-radius:6px;overflow:hidden}
.msi__side{background:#faf9f7;border-bottom:1px solid rgba(10,10,10,.1);padding:10px 14px}
.msi__brand{margin:0 0 8px;font:500 10px 'JetBrains Mono',monospace;letter-spacing:.1em;text-transform:uppercase;color:#5a5a5a}
.msi__steps{list-style:none;margin:0;padding:0;display:flex;gap:4px}
.msi__steps li{flex:1;min-width:0}
.msi__st{display:flex;align-items:center;gap:7px;width:100%;font:600 12.5px 'Switzer',system-ui,sans-serif;color:#0a0a0a;background:none;border:0;border-radius:4px;padding:4px;cursor:pointer;text-align:left;transition:background .15s}
.msi__st:hover:not(:disabled){background:#efede9}
.msi__st:disabled{cursor:default;color:#6b6b6b}
.msi__st-n{flex:none;display:grid;place-items:center;width:22px;height:22px;border-radius:50%;border:1.5px solid #9a9a9a;font:700 11px 'JetBrains Mono',monospace;color:#5a5a5a;background:#fff}
.msi__st[aria-current="step"] .msi__st-n{border-color:#0a0a0a;background:#0a0a0a;color:#fff}
.msi__st[data-s="done"] .msi__st-n{border-color:#146C43;background:#146C43;color:#fff;font-size:0}
.msi__st[data-s="done"] .msi__st-n::before{content:'';width:9px;height:5px;border:2px solid #fff;border-top:0;border-right:0;transform:rotate(-45deg) translate(1px,-1px)}
.msi__st-t{display:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.msi__st[aria-current="step"] .msi__st-t{display:inline}
.msi__bar{height:4px;background:#e7e4df;border-radius:2px;margin-top:8px;overflow:hidden}
.msi__bar i{display:block;height:100%;width:0;background:#F5480F;transition:width .35s cubic-bezier(.2,.8,.2,1)}
.msi__tip{display:none;margin:12px 0 0;font-size:12px;line-height:1.45;color:#5a5a5a}
@container (min-width:600px){.msi__card{grid-template-columns:190px 1fr}.msi__side{border-bottom:0;border-right:1px solid rgba(10,10,10,.1);padding:16px}.msi__steps{flex-direction:column;gap:2px}.msi__st{padding:7px 6px}.msi__st-t{display:inline}.msi__tip{display:block}}
.msi__form{padding:14px 16px;min-width:0}
.msi__count{margin:0 0 4px;font:500 10.5px 'JetBrains Mono',monospace;letter-spacing:.08em;text-transform:uppercase;color:#5a5a5a}
.msi__pane{border:0;margin:0;padding:0;min-width:0}
.msi__pane:focus{outline:none}
.msi__h{font-size:16px;font-weight:700;letter-spacing:-.01em;padding:0;margin:0 0 10px}
.msi__l{display:block;font-size:12.5px;font-weight:600;margin:8px 0 4px}
.msi__l small{font-weight:400;color:#5a5a5a}
.msi__i{display:block;width:100%;font:400 14px/1.4 'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#fff;border:1px solid #8c8c8c;border-radius:4px;padding:8px 10px;resize:vertical;transition:border-color .15s,box-shadow .15s}
.msi__i:hover{border-color:#0a0a0a}
.msi__i:focus-visible{outline:none;border-color:#0a0a0a;box-shadow:0 0 0 3px rgba(245,72,15,.35)}
.msi__i[aria-invalid="true"]{border-color:#B42318}
.msi__two{display:grid;gap:0 12px}
@container (min-width:420px){.msi__two{grid-template-columns:1fr 1fr}}
.msi__chips{display:flex;flex-wrap:wrap;gap:6px}
.msi__chip{position:relative;cursor:pointer}
.msi__chip input{position:absolute;opacity:0;width:1px;height:1px}
.msi__chip span{display:inline-block;font-size:13px;padding:6px 12px;border:1px solid #8c8c8c;border-radius:100px;background:#fff;transition:background .15s,border-color .15s,color .15s}
.msi__chip:hover span{border-color:#0a0a0a}
.msi__chip input:checked+span{background:#0a0a0a;border-color:#0a0a0a;color:#fff}
.msi__chip input:focus-visible+span{outline:2px solid #F5480F;outline-offset:2px}
.msi__chip input[aria-invalid="true"]+span{border-color:#B42318}
.msi__row{display:flex;justify-content:space-between;gap:8px;align-items:flex-start}
.msi__cnt{flex:none;margin-top:4px;font:500 11px 'JetBrains Mono',monospace;color:#5a5a5a}
.msi__cnt.is-near{color:#8A4B00}
.msi__e{margin:4px 0 0;font-size:12px;color:#B42318}
.msi__e:empty{display:none}
.msi__dl{margin:0;display:grid;gap:6px}
.msi__dl div{display:grid;grid-template-columns:1fr auto;gap:2px 10px;padding:7px 0;border-bottom:1px solid rgba(10,10,10,.1);font-size:13px}
.msi__dl dt{font-size:11.5px;color:#5a5a5a;grid-column:1}
.msi__dl dd{margin:0;grid-column:1;overflow-wrap:anywhere}
.msi__dl button{grid-column:2;grid-row:1/span 2;align-self:center;font:600 12px 'Switzer',system-ui,sans-serif;background:none;border:0;color:#0a0a0a;text-decoration:underline;cursor:pointer;padding:4px}
.msi__act{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:14px}
.msi__back,.msi__save,.msi__next,.msi__new{font:600 13px 'Switzer',system-ui,sans-serif;border-radius:4px;padding:8px 14px;cursor:pointer;transition:background .15s,color .15s,border-color .15s}
.msi__back{background:#fff;border:1px solid #8c8c8c;color:#0a0a0a}
.msi__back:hover{border-color:#0a0a0a}
.msi__save{background:none;border:0;color:#0a0a0a;text-decoration:underline;text-underline-offset:3px;padding:8px 4px}
.msi__next{margin-left:auto;display:inline-flex;align-items:center;gap:8px;background:#0a0a0a;border:1px solid #0a0a0a;color:#fff}
.msi__next:hover{background:#F5480F;border-color:#F5480F;color:#0a0a0a}
.msi__next[aria-busy="true"]{background:#0a0a0a;color:#fff;cursor:progress}
.msi__spin{display:none;width:13px;height:13px;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:msi-spin .7s linear infinite}
.msi__next[aria-busy="true"] .msi__spin{display:inline-block}
@keyframes msi-spin{to{transform:rotate(360deg)}}
.msi__back:focus-visible,.msi__save:focus-visible,.msi__next:focus-visible,.msi__new:focus-visible,.msi__st:focus-visible,.msi__wis:focus-visible,.msi__dl button:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.msi__live{margin:8px 0 0;font-size:12px;color:#146C43;min-height:1em}
.msi__live.is-err{color:#B42318}
.msi__done{grid-column:1/-1;text-align:center;padding:28px 16px;font-size:13.5px;color:#3d3d3d}
.msi__done:focus{outline:none}
.msi__done svg{width:44px;height:44px;fill:none;stroke:#146C43;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.msi__done .msi__h{margin:6px 0 4px;color:#0a0a0a}
.msi__new{margin-top:10px;background:#fff;border:1px solid #0a0a0a;color:#0a0a0a}
.msi__new:hover{background:#0a0a0a;color:#fff}
.msi__card.is-done .msi__side,.msi__card.is-done .msi__form{display:none}
@media (prefers-reduced-motion:reduce){.msi *{transition:none!important;animation:none!important}}// Meerstaps intake met concept · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root=root.querySelector('.msi')||root;
(function(r){var s='-'+Math.random().toString(36).slice(2,7);r.querySelectorAll('[id]').forEach(function(el){var o=el.id,n=o+s;el.id=n;['for','aria-describedby','aria-labelledby','aria-controls','popovertarget'].forEach(function(a){r.querySelectorAll('['+a+']').forEach(function(x){x.setAttribute(a,x.getAttribute(a).split(' ').map(function(t){return t===o?n:t;}).join(' '));});});});})(root);
var KEY='ndl-lab-msi-concept',form=root.querySelector('.msi__form'),panes=[].slice.call(root.querySelectorAll('.msi__pane')),sts=[].slice.call(root.querySelectorAll('.msi__st')),bar=root.querySelector('.msi__bar'),fill=bar.querySelector('i'),cnt=root.querySelector('.msi__count b'),back=root.querySelector('.msi__back'),save=root.querySelector('.msi__save'),next=root.querySelector('.msi__next'),nextT=root.querySelector('.msi__next-t'),live=root.querySelector('.msi__live'),dl=root.querySelector('.msi__dl'),card=root.querySelector('.msi__card'),done=root.querySelector('.msi__done'),rest=root.querySelector('.msi__restore'),restT=root.querySelector('.msi__restore-t'),ta=form.elements.klacht,taC=root.querySelector('.msi__cnt');
var NAMES=['plek','klacht','naam','geb','email','zv','aanv'],cur=0,max=0,busy=false;
var DAG=['zo','ma','di','wo','do','vr','za'],MND=['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'];
function val(n){var el=form.elements[n];return el?String(el.value||'').trim():'';}
function setv(n,v){var el=form.elements[n];if(el)el.value=v||'';}
function list(n){var el=form.elements[n];return !el?[]:(el.tagName?[el]:[].slice.call(el));}
function err(n,msg){var p=form.querySelector('[data-e="'+n+'"]');if(p)p.textContent=msg||'';list(n).forEach(function(x){if(msg)x.setAttribute('aria-invalid','true');else x.removeAttribute('aria-invalid');});return !msg;}
var RULES=[function(){var a=err('plek',val('plek')?'':'Kies waar je last van hebt'),k=val('klacht'),b=err('klacht',k.length>=10?'':(k?'Nog '+(10-k.length)+' tekens, dan kunnen we je beter helpen':'Omschrijf kort je klacht'));return a&&b;},
function(){var a=err('naam',val('naam').length>1?'':'Vul je naam in'),g=val('geb'),d=g?new Date(g):null,ok=d&&!isNaN(d)&&d<new Date()&&d.getFullYear()>1900,b=err('geb',ok?'':(g?'Deze datum klopt niet':'Vul je geboortedatum in')),e=val('email'),c=err('email',/^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i.test(e)?'':(e?'Dit e-mailadres is niet compleet':'Vul je e-mailadres in'));return a&&b&&c;},
function(){var a=err('zv',val('zv')?'':'Kies je zorgverzekeraar'),b=err('aanv',val('aanv')?'':'Kies een antwoord');return a&&b;},
function(){return true;}];
function counter(){var n=ta.value.length;taC.textContent=n+'/250 tekens';taC.classList.toggle('is-near',n>=225);}
function fmtGeb(g){var p=g.split('-');return p.length===3?p[2]+'-'+p[1]+'-'+p[0]:g;}
function review(){var rows=[['Klacht',val('plek')+': '+val('klacht'),0],['Naam',val('naam'),1],['Geboortedatum',fmtGeb(val('geb')),1],['E-mailadres',val('email'),1],['Verzekering',val('zv')+', aanvullend: '+val('aanv').toLowerCase(),2]];
dl.innerHTML='';rows.forEach(function(r){var d=document.createElement('div');d.innerHTML='<dt></dt><dd></dd><button type="button" data-go="'+r[2]+'">Wijzig</button>';d.querySelector('dt').textContent=r[0];d.querySelector('dd').textContent=r[1];d.querySelector('button').setAttribute('aria-label','Wijzig '+r[0].toLowerCase());dl.appendChild(d);});}
function go(i,focus){cur=i;max=Math.max(max,i);panes.forEach(function(p,j){p.hidden=j!==i;});
sts.forEach(function(b,j){b.removeAttribute('aria-current');b.removeAttribute('data-s');b.disabled=j>max;if(j===i)b.setAttribute('aria-current','step');else if(j<max||j<i)b.setAttribute('data-s','done');var t=b.querySelector('.msi__st-t').textContent;b.setAttribute('aria-label','Stap '+(j+1)+', '+t+(j===i?', huidige stap':(b.dataset.s?', afgerond':(b.disabled?', nog niet beschikbaar':''))));});
var pct=Math.round(i/4*100);fill.style.width=pct+'%';bar.setAttribute('aria-valuenow',pct);cnt.textContent=i+1;back.style.visibility=i?'visible':'hidden';nextT.textContent=i===3?'Verstuur intake':'Volgende';
if(i===3)review();if(focus)panes[i].focus();}
sts.forEach(function(b){b.addEventListener('click',function(){if(!busy)go(+b.dataset.go,true);});});
dl.addEventListener('click',function(e){var b=e.target.closest('[data-go]');if(b)go(+b.dataset.go,true);});
back.addEventListener('click',function(){if(cur&&!busy)go(cur-1,true);});
ta.addEventListener('input',counter);
form.addEventListener('input',function(e){var n=e.target.name;if(n&&e.target.getAttribute('aria-invalid'))RULES[cur]();});
form.addEventListener('change',function(e){var n=e.target.name;if(n&&(e.target.type==='radio'||e.target.tagName==='SELECT'))err(n,'');});
form.addEventListener('submit',function(e){e.preventDefault();if(busy)return;live.textContent='';live.classList.remove('is-err');
if(cur<3){if(RULES[cur]())go(cur+1,true);else{var f=panes[cur].querySelector('[aria-invalid="true"]');if(f)f.focus();}return;}
busy=true;next.setAttribute('aria-busy','true');nextT.textContent='Versturen…';
setTimeout(function(){busy=false;next.removeAttribute('aria-busy');try{localStorage.removeItem(KEY);}catch(_){}rest.hidden=true;fill.style.width='100%';card.classList.add('is-done');done.hidden=false;done.focus();},1100);});
function stamp(t){var d=new Date(t);return DAG[d.getDay()]+' '+d.getDate()+' '+MND[d.getMonth()]+' om '+String(d.getHours()).padStart(2,'0')+':'+String(d.getMinutes()).padStart(2,'0');}
save.addEventListener('click',function(){var v={};NAMES.forEach(function(n){v[n]=val(n);});
try{localStorage.setItem(KEY,JSON.stringify({v:v,s:cur,m:max,t:Date.now()}));live.classList.remove('is-err');live.textContent='Opgeslagen '+stamp(Date.now())+'. Kom terug wanneer je wilt, je gaat verder bij stap '+(cur+1)+'.';}
catch(_){live.classList.add('is-err');live.textContent='Opslaan lukt niet in deze browser, bijvoorbeeld in privémodus. Laat dit venster open of rond de intake nu af.';}});
function clearForm(){form.reset();NAMES.forEach(function(n){err(n,'');});counter();max=0;}
root.querySelector('.msi__wis').addEventListener('click',function(){try{localStorage.removeItem(KEY);}catch(_){}clearForm();rest.hidden=true;go(0,true);live.textContent='Concept gewist.';});
root.querySelector('.msi__new').addEventListener('click',function(){clearForm();card.classList.remove('is-done');done.hidden=true;go(0,true);live.textContent='';});
var raw=null;try{raw=localStorage.getItem(KEY);}catch(_){}
if(raw){try{var o=JSON.parse(raw);NAMES.forEach(function(n){setv(n,o.v[n]);});counter();max=o.m||0;go(o.s||0,false);restT.textContent='Je concept van '+stamp(o.t)+' is teruggezet.';rest.hidden=false;}catch(_){go(0,false);}}else go(0,false);
counter();
}
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 →