Boekingsbevestiging met agenda-bestand Nieuw
Bevestigingspagina na het boeken (hier een fysiopraktijk): samenvattingskaart met wat, wanneer, waar en met wie, een knop die een echt .ics-agendabestand maakt (Blob-download, tijd correct omgerekend vanuit Nederlandse tijd), een Google Agenda-link, routeplanner-link en verzetten of annuleren zonder pagina te verlaten. Staten: bevestigd, verzet, geannuleerd. Vinkje tekent zich één keer (uit bij prefers-reduced-motion); lay-out via container queries met media-query-fallback.
Fysiotherapie Kralingen · boeking FK-24817
Je afspraak staat vast
We hebben een bevestiging gestuurd naar j.devries@voorbeeld.nl. Een dag van tevoren krijg je een herinnering per sms.
- Wat
- Intake en eerste behandeling45 minuten · rug en schouder
- Wanneer
- Waar
- Oudedijk 112, 3061 AN RotterdamIngang naast de apotheek, eerste verdieping
- Met
- Lotte BakkerSportfysiotherapeut, 12 jaar ervaring
- Kosten
- € 49,00We declareren rechtstreeks bij je zorgverzekeraar
Zo bereid je je voor
- Kom vijf minuten eerder. Dan nemen we samen je klachten en medicatie door.
- Draag makkelijk zittende kleding. Een korte broek of hemd is handig bij rug- en schouderklachten.
- Verwijzing van de huisarts? Niet nodig. Heb je er wel een, neem hem dan mee.
Parkeren Blauwe zone voor de deur, 2 uur gratis met parkeerschijf. Tramhalte Oudedijk ligt op 3 minuten lopen (lijn 21).
Vragen of later? Bel 010 123 4567 of mail praktijk@voorbeeld.nl. Kosteloos verzetten kan tot 24 uur vooraf.
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.
<!-- Boekingsbevestiging met agenda-bestand · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="bbv"><div class="bbv__in"><div class="bbv__main"><div class="bbv__status"><span class="bbv__ic" aria-hidden="true"><svg viewBox="0 0 40 40" width="40" height="40"><circle cx="20" cy="20" r="18" fill="none" stroke="currentColor" stroke-width="2"/><path class="bbv__tick" d="M12.5 20.5l5 5 10-11" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg></span><div><p class="bbv__k">Fysiotherapie Kralingen · boeking <span class="bbv__nr">FK-24817</span></p><h2 class="bbv__h" tabindex="-1">Je afspraak staat vast</h2><p class="bbv__lead">We hebben een bevestiging gestuurd naar <b>j.devries@voorbeeld.nl</b>. Een dag van tevoren krijg je een herinnering per sms.</p></div></div><div class="bbv__card"><dl class="bbv__dl"><div><dt>Wat</dt><dd>Intake en eerste behandeling<span>45 minuten · rug en schouder</span></dd></div><div><dt>Wanneer</dt><dd class="bbv__when"></dd></div><div><dt>Waar</dt><dd>Oudedijk 112, 3061 AN Rotterdam<span>Ingang naast de apotheek, eerste verdieping</span></dd></div><div><dt>Met</dt><dd>Lotte Bakker<span>Sportfysiotherapeut, 12 jaar ervaring</span></dd></div><div><dt>Kosten</dt><dd>€ 49,00<span>We declareren rechtstreeks bij je zorgverzekeraar</span></dd></div></dl><div class="bbv__acts"><button type="button" class="bbv__btn bbv__btn--p bbv__ics"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><rect x="2" y="3" width="12" height="11" rx="1.5"/><path d="M2 6.5h12M5.5 1.5v3M10.5 1.5v3M8 8.5v3.5M6.3 10.3 8 12l1.7-1.7"/></svg>Zet in je agenda (.ics)</button><a class="bbv__btn bbv__gcal" target="_blank" rel="noopener">Google Agenda</a><a class="bbv__btn bbv__route" target="_blank" rel="noopener" href="https://www.google.com/maps/dir/?api=1&destination=Oudedijk%20112%2C%203061%20AN%20Rotterdam"><svg width="14" height="14" 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>Route plannen</a><span class="bbv__more"><button type="button" class="bbv__lnk bbv__mv" aria-expanded="false" aria-controls="bbv-mv">Verzetten</button><button type="button" class="bbv__lnk bbv__cx" aria-expanded="false" aria-controls="bbv-cx">Annuleren</button></span></div><div class="bbv__pane" id="bbv-mv" hidden><fieldset class="bbv__fs"><legend>Kies een nieuwe tijd bij Lotte</legend><div class="bbv__alts"></div></fieldset><div class="bbv__pa"><button type="button" class="bbv__btn bbv__btn--p bbv__mvok">Nieuwe tijd bevestigen</button><button type="button" class="bbv__lnk bbv__close">Toch niet</button></div></div><div class="bbv__pane bbv__pane--cx" id="bbv-cx" hidden><p class="bbv__warn"></p><div class="bbv__pa"><button type="button" class="bbv__btn bbv__btn--d bbv__cxok">Ja, annuleer afspraak</button><button type="button" class="bbv__lnk bbv__close">Nee, ik kom</button></div></div></div><p class="bbv__toast" role="status" aria-live="polite"></p></div><div class="bbv__side"><p class="bbv__sh">Zo bereid je je voor</p><ol class="bbv__prep"><li><b>Kom vijf minuten eerder.</b> Dan nemen we samen je klachten en medicatie door.</li><li><b>Draag makkelijk zittende kleding.</b> Een korte broek of hemd is handig bij rug- en schouderklachten.</li><li><b>Verwijzing van de huisarts?</b> Niet nodig. Heb je er wel een, neem hem dan mee.</li></ol><div class="bbv__info"><p><b>Parkeren</b> Blauwe zone voor de deur, 2 uur gratis met parkeerschijf. Tramhalte Oudedijk ligt op 3 minuten lopen (lijn 21).</p><p><b>Vragen of later?</b> Bel <a href="tel:+31101234567">010 123 4567</a> of mail <a href="mailto:praktijk@voorbeeld.nl">praktijk@voorbeeld.nl</a>. Kosteloos verzetten kan tot 24 uur vooraf.</p></div></div></div></div>
</div>/* Boekingsbevestiging met agenda-bestand · NedDev · eigen werk. */
/* fonts (Fontshare): erode@500,600 */
.bbv{--ink:#13241c;--mut:#4d5a52;--acc:#2f6b4f;--acc2:#e3eee6;--bg:#f3f1ea;--line:rgba(19,36,28,.14);--red:#b42318;background:var(--bg);color:var(--ink);font-family:'Switzer',system-ui,sans-serif;container-type:inline-size}
.bbv__in{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(0,1fr);gap:48px;max-width:1180px;margin:0 auto;padding:44px 48px 48px}
.bbv__status{display:flex;gap:16px;align-items:flex-start;margin-bottom:22px}
.bbv__ic{flex:none;color:var(--acc);margin-top:2px}
.bbv__tick{stroke-dasharray:30;stroke-dashoffset:0}
@media (prefers-reduced-motion:no-preference){.bbv__tick{animation:bbv-draw .6s .25s cubic-bezier(.3,.7,.3,1) both}}
@keyframes bbv-draw{from{stroke-dashoffset:30}}
.bbv.is-cx .bbv__ic{color:var(--mut)}
.bbv__k{margin:0 0 4px;font:500 11px 'JetBrains Mono',monospace;letter-spacing:.06em;text-transform:uppercase;color:var(--mut)}
.bbv__h{margin:0;font-family:'Erode',Georgia,serif;font-weight:600;font-size:38px;line-height:1.05;letter-spacing:-.01em;outline:none}
.bbv__lead{margin:10px 0 0;font-size:15px;line-height:1.5;color:var(--mut);max-width:52ch}
.bbv__lead b{color:var(--ink);font-weight:600}
.bbv__card{background:#fff;border:1px solid var(--line);border-radius:6px;box-shadow:0 1px 0 var(--line)}
.bbv__dl{margin:0;padding:6px 22px}
.bbv__dl>div{display:grid;grid-template-columns:96px 1fr;gap:12px;padding:13px 0;border-bottom:1px solid var(--line)}
.bbv__dl>div:last-child{border-bottom:0}
.bbv__dl dt{font:500 11px/20px 'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:.06em;color:var(--mut)}
.bbv__dl dd{margin:0;font-size:15px;font-weight:600;line-height:1.4;font-variant-numeric:tabular-nums}
.bbv__dl dd span{display:block;font-weight:400;font-size:13px;color:var(--mut)}
.bbv__when s{color:var(--mut);font-weight:400}
.bbv.is-cx .bbv__dl dd{color:var(--mut)}
.bbv__acts{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:16px 22px;border-top:1px solid var(--line);background:#fbfaf6;border-radius:0 0 6px 6px}
.bbv__more{display:flex;gap:2px;margin-left:auto}
.bbv__btn{display:inline-flex;align-items:center;gap:7px;height:40px;padding:0 13px;border:1px solid var(--ink);border-radius:4px;background:#fff;color:var(--ink);font:600 14px 'Switzer',system-ui,sans-serif;text-decoration:none;cursor:pointer;transition:background-color .15s,color .15s,border-color .15s}
.bbv__btn:hover{background:var(--acc2)}
.bbv__btn:active{transform:translateY(1px)}
.bbv__btn:focus-visible,.bbv__lnk:focus-visible,.bbv__info a:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.bbv__btn--p{background:var(--acc);border-color:var(--acc);color:#fff}
.bbv__btn--p:hover{background:var(--ink);border-color:var(--ink);color:#fff}
.bbv__btn--d{background:var(--red);border-color:var(--red);color:#fff}
.bbv__btn--d:hover{background:#8a1a12;border-color:#8a1a12}
.bbv__btn:disabled{opacity:.5;cursor:not-allowed}
.bbv__lnk{height:40px;padding:0 8px;border:0;background:none;color:var(--ink);font:600 14px 'Switzer',system-ui,sans-serif;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;cursor:pointer;border-radius:4px;transition:background-color .15s}
.bbv__lnk:hover{background:rgba(19,36,28,.06)}
.bbv__cx{color:var(--red)}
.bbv__pane{padding:16px 22px 18px;border-top:1px solid var(--line)}
.bbv__pane[hidden]{display:none}
.bbv__fs{margin:0;padding:0;border:0}
.bbv__fs legend{padding:0;margin-bottom:10px;font-weight:600;font-size:14px}
.bbv__alts{display:flex;flex-wrap:wrap;gap:8px}
.bbv__alt{position:relative}
.bbv__alt input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer}
.bbv__alt span{display:block;padding:8px 12px;border:1px solid var(--line);border-radius:4px;background:#fff;font-size:13.5px;font-weight:600;font-variant-numeric:tabular-nums;transition:border-color .15s,background-color .15s}
.bbv__alt:hover span{border-color:var(--ink)}
.bbv__alt input:focus-visible+span{outline:2px solid var(--ink);outline-offset:2px}
.bbv__alt input:checked+span{background:var(--ink);border-color:var(--ink);color:#fff}
.bbv__pa{display:flex;gap:8px;margin-top:14px;align-items:center}
.bbv__warn{margin:0;font-size:14px;line-height:1.5}
.bbv__toast{min-height:20px;margin:12px 0 0;font-size:13.5px;color:var(--acc);font-weight:600}
.bbv__side{padding-top:8px}
.bbv__sh{margin:0 0 14px;font-family:'Erode',Georgia,serif;font-size:22px;font-weight:600}
.bbv__prep{margin:0 0 22px;padding:0;list-style:none;counter-reset:bbv}
.bbv__prep li{position:relative;padding:0 0 14px 40px;margin-bottom:14px;border-bottom:1px solid var(--line);font-size:14px;line-height:1.5;color:var(--mut);counter-increment:bbv}
.bbv__prep li::before{content:counter(bbv,decimal-leading-zero);position:absolute;left:0;top:1px;font:500 12px 'JetBrains Mono',monospace;color:var(--acc)}
.bbv__prep b{display:block;color:var(--ink);font-weight:600}
.bbv__info{padding:16px 18px;border-radius:6px;background:var(--acc2);font-size:13.5px;line-height:1.55}
.bbv__info p{margin:0}
.bbv__info p+p{margin-top:10px}
.bbv__info b{display:block;font-weight:600}
.bbv__info a{color:var(--ink);font-weight:600;text-underline-offset:2px}
@container (max-width:820px){.bbv__in{grid-template-columns:1fr;gap:28px;padding:28px 16px 32px}.bbv__h{font-size:28px}.bbv__dl{padding:4px 16px}.bbv__dl>div{grid-template-columns:1fr;gap:2px}.bbv__acts{padding:14px 16px}.bbv__btn{flex:1 1 100%;justify-content:center}.bbv__more{margin-left:0}.bbv__pane{padding:14px 16px}.bbv__pa{flex-wrap:wrap}}
@supports not (container-type:inline-size){@media (max-width:820px){.bbv__in{grid-template-columns:1fr;padding:28px 16px}.bbv__btn{flex:1 1 100%;justify-content:center}}}
@media (prefers-reduced-motion:reduce){.bbv *{transition:none!important}}// Boekingsbevestiging met agenda-bestand · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.bbv');if(!w)return;
var when=w.querySelector('.bbv__when'),toast=w.querySelector('.bbv__toast'),mvB=w.querySelector('.bbv__mv'),cxB=w.querySelector('.bbv__cx'),mv=w.querySelector('#bbv-mv'),cx=w.querySelector('#bbv-cx'),alts=w.querySelector('.bbv__alts'),gcal=w.querySelector('.bbv__gcal'),h=w.querySelector('.bbv__h'),lead=w.querySelector('.bbv__lead');
var DAGL=['zondag','maandag','dinsdag','woensdag','donderdag','vrijdag','zaterdag'],DAG=['zo','ma','di','wo','do','vr','za'],MND=['januari','februari','maart','april','mei','juni','juli','augustus','september','oktober','november','december'],MK=['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'];
var DUR=45,NR='FK-24817',TITLE='Intake fysiotherapie, Fysiotherapie Kralingen',ADDR='Oudedijk 112, 3061 AN Rotterdam';
function day(n){var d=new Date();d.setHours(0,0,0,0);d.setDate(d.getDate()+n);while(d.getDay()===0||d.getDay()===6)d.setDate(d.getDate()+1);return d}
/* afspraak in Nederlandse tijd: {y,m,d,h,mi} */
function slot(d,h,mi){return {y:d.getFullYear(),m:d.getMonth(),d:d.getDate(),h:h,mi:mi,dow:d.getDay()}}
var cur=slot(day(8),14,30);
function hm(h,m){return ('0'+h).slice(-2)+':'+('0'+m).slice(-2)}
function endOf(s){var t=s.h*60+s.mi+DUR;return [t/60|0,t%60]}
function label(s){var e=endOf(s);return DAGL[s.dow]+' '+s.d+' '+MND[s.m]+' '+s.y+', '+hm(s.h,s.mi)+' tot '+hm(e[0],e[1])}
/* Nederlandse wandkloktijd naar UTC, ook als de bezoeker in een andere tijdzone zit */
function utc(s,addMin){var guess=Date.UTC(s.y,s.m,s.d,s.h,s.mi+(addMin||0));var off=0;try{var p={};new Intl.DateTimeFormat('en-GB',{timeZone:'Europe/Amsterdam',hourCycle:'h23',year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'}).formatToParts(new Date(guess)).forEach(function(x){p[x.type]=x.value});off=Date.UTC(+p.year,+p.month-1,+p.day,+p.hour,+p.minute)-guess}catch(e){off=new Date(guess).getTimezoneOffset()*-60000}return new Date(guess-off)}
function stamp(d){return d.toISOString().replace(/[-:]/g,'').replace(/\.\d{3}/,'')}
function esc(t){return t.replace(/\\/g,'\\\\').replace(/,/g,'\\,').replace(/;/g,'\\;')}
function ics(s){var a=utc(s),b=utc(s,DUR);return ['BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//NedDev Lab//Boekingsbevestiging//NL','CALSCALE:GREGORIAN','METHOD:PUBLISH','BEGIN:VEVENT','UID:'+NR+'@voorbeeld.nl','DTSTAMP:'+stamp(new Date()),'DTSTART:'+stamp(a),'DTEND:'+stamp(b),'SUMMARY:'+esc(TITLE),'LOCATION:'+esc(ADDR),'DESCRIPTION:'+esc('Boekingsnummer '+NR+'. Met Lotte Bakker. Verzetten of annuleren kan tot 24 uur vooraf via 010 123 4567.'),'BEGIN:VALARM','TRIGGER:-PT1H','ACTION:DISPLAY','DESCRIPTION:'+esc('Over een uur: fysiotherapie'),'END:VALARM','END:VEVENT','END:VCALENDAR'].join('\r\n')+'\r\n'}
function say(t){toast.textContent='';setTimeout(function(){toast.textContent=t},30)}
function render(old){when.innerHTML=(old?'<s>'+label(old)+'</s><br>':'')+label(cur)+'<span>Nederlandse tijd</span>';
gcal.href='https://calendar.google.com/calendar/render?action=TEMPLATE&text='+encodeURIComponent(TITLE)+'&dates='+stamp(utc(cur))+'/'+stamp(utc(cur,DUR))+'&location='+encodeURIComponent(ADDR)+'&details='+encodeURIComponent('Boekingsnummer '+NR)}
w.querySelector('.bbv__ics').addEventListener('click',function(){var blob=new Blob([ics(cur)],{type:'text/calendar;charset=utf-8'}),url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download='afspraak-'+NR.toLowerCase()+'.ics';document.body.appendChild(a);a.click();a.remove();setTimeout(function(){URL.revokeObjectURL(url)},1500);say('Agendabestand gedownload. Open het om de afspraak toe te voegen.')});
function toggle(btn,pane,other,otherBtn){var open=pane.hidden;pane.hidden=!open;btn.setAttribute('aria-expanded',open);other.hidden=true;otherBtn.setAttribute('aria-expanded','false');if(open){var f=pane.querySelector('input:checked,input,button');if(f)f.focus()}}
mvB.addEventListener('click',function(){toggle(mvB,mv,cx,cxB)});
cxB.addEventListener('click',function(){var dl=new Date(utc(cur).getTime()-864e5);w.querySelector('.bbv__warn').innerHTML='Weet je het zeker? Kosteloos annuleren kan tot <b>'+DAG[dl.getDay()]+' '+dl.getDate()+' '+MK[dl.getMonth()]+' '+hm(cur.h,cur.mi)+'</b>. Daarna rekenen we € 25,00.';toggle(cxB,cx,mv,mvB)});
w.querySelectorAll('.bbv__close').forEach(function(b){b.addEventListener('click',function(){var p=b.closest('.bbv__pane');p.hidden=true;var t=p===mv?mvB:cxB;t.setAttribute('aria-expanded','false');t.focus()})});
var A=[slot(day(8),9,15),slot(day(9),16,0),slot(day(11),11,30),slot(day(12),8,30)];
alts.innerHTML=A.map(function(s,i){return '<label class="bbv__alt"><input type="radio" name="bbv-alt" value="'+i+'"'+(i===0?' checked':'')+'><span>'+DAG[s.dow]+' '+s.d+' '+MK[s.m]+' · '+hm(s.h,s.mi)+'</span></label>'}).join('');
w.querySelector('.bbv__mvok').addEventListener('click',function(){var i=+w.querySelector('input[name="bbv-alt"]:checked').value,old=cur;cur=A[i];A[i]=old;alts.querySelectorAll('span')[i].textContent=DAG[old.dow]+' '+old.d+' '+MK[old.m]+' · '+hm(old.h,old.mi);render(old);mv.hidden=true;mvB.setAttribute('aria-expanded','false');h.textContent='Je afspraak is verzet';h.focus();say('Verzet. Je ontvangt een nieuwe bevestiging; download ook het nieuwe agendabestand.')});
w.querySelector('.bbv__cxok').addEventListener('click',function(){w.classList.add('is-cx');w.querySelector('.bbv__tick').setAttribute('d','M14 14l12 12M26 14 14 26');cx.hidden=true;h.textContent='Je afspraak is geannuleerd';lead.innerHTML='Er worden geen kosten in rekening gebracht. We hebben een annuleringsmail gestuurd naar <b>j.devries@voorbeeld.nl</b>.';
var acts=w.querySelector('.bbv__acts');acts.innerHTML='<button type="button" class="bbv__btn bbv__btn--p bbv__again">Nieuwe afspraak maken</button>';acts.querySelector('.bbv__again').addEventListener('click',function(){say('Hier ga je naar de agenda van de praktijk.')});when.innerHTML='<s>'+label(cur)+'</s>';h.focus();say('Afspraak geannuleerd.')});
render();
}
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 →