Chatvenster in WhatsApp-stijl Nieuw
Chatvenster in de stijl van een berichtenapp (zonder merklogo of merkkleur): bubbels met staartje, tijd en vinkjes (verzonden, afgeleverd, gelezen), een typindicator, snelle antwoorden en een composer waarvan de verzendknop pas actief wordt met tekst. "Ga verder in WhatsApp" bouwt een wa.me-link met je gesprek. Het berichtenlog is role="log" met aria-live; de antwoorden zijn demo-teksten.
Hendriks InstallatieReageert meestal binnen 10 min
Ga verder in WhatsAppWhatsAppVandaag
Goedemiddag, je spreekt met Ruben van Hendriks Installatie. Waarmee kan ik helpen?
Mijn cv-ketel geeft code F28 en de radiatoren blijven koud.
Vervelend. F28 betekent meestal dat de ketel niet ontsteekt. Staat de gaskraan open?
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.
<!-- Chatvenster in WhatsApp-stijl · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="cwa"><div class="cwa__win">
<div class="cwa__head"><span class="cwa__av" aria-hidden="true">RH</span><div class="cwa__who"><b>Hendriks Installatie</b><span class="cwa__stat">Reageert meestal binnen 10 min</span></div><a class="cwa__wa" href="https://wa.me/31101234567" target="_blank" rel="noopener"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1.5a6.5 6.5 0 0 0-5.6 9.8L1.5 14.5l3.3-.9A6.5 6.5 0 1 0 8 1.5z"/></svg><span class="cwa__wa-l">Ga verder in WhatsApp</span><span class="cwa__wa-s">WhatsApp</span></a></div>
<div class="cwa__log" role="log" aria-live="polite" aria-label="Gesprek met Hendriks Installatie" tabindex="0">
<p class="cwa__day">Vandaag</p>
<div class="cwa__m cwa__m--them"><p>Goedemiddag, je spreekt met Ruben van Hendriks Installatie. Waarmee kan ik helpen?</p><span class="cwa__meta"><time>14:02</time></span></div>
<div class="cwa__m cwa__m--me"><p>Mijn cv-ketel geeft code F28 en de radiatoren blijven koud.</p><span class="cwa__meta"><time>14:03</time><span class="cwa__tick" data-s="read" role="img" aria-label="Gelezen"><svg viewBox="0 0 18 10" aria-hidden="true"><path class="cwa__t1" d="M1 5.5l3 3 6-7"/><path class="cwa__t2" d="M7 8.5l1 0.2 6-7.2"/></svg></span></span></div>
<div class="cwa__m cwa__m--them"><p>Vervelend. F28 betekent meestal dat de ketel niet ontsteekt. Staat de gaskraan open?</p><span class="cwa__meta"><time>14:04</time></span></div>
<div class="cwa__typing" aria-hidden="true" hidden><i></i><i></i><i></i></div>
</div>
<div class="cwa__quick" role="group" aria-label="Snelle antwoorden"><button type="button">Ja, die staat open</button><button type="button">Kan er vandaag iemand komen?</button><button type="button">Wat kost een monteur?</button></div>
<form class="cwa__comp"><label class="cwa__sr" for="cwa-in">Bericht aan Hendriks Installatie</label><textarea class="cwa__in" id="cwa-in" rows="1" placeholder="Typ een bericht"></textarea><button class="cwa__send" type="submit" disabled aria-label="Verstuur bericht"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2 8l12-6-4.5 12-2-5z"/></svg></button></form>
</div></div>
</div>/* Chatvenster in WhatsApp-stijl · NedDev · eigen werk. */
.cwa [hidden]{display:none!important}
.cwa{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:10px;box-sizing:border-box;background:#f4f3f1;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;container-type:inline-size}
.cwa *,.cwa *::before,.cwa *::after{box-sizing:border-box}
.cwa__win{width:100%;max-width:440px;height:100%;max-height:560px;display:flex;flex-direction:column;background:#ece7df;border:1px solid rgba(10,10,10,.14);border-radius:8px;overflow:hidden}
.cwa__head{flex:none;display:flex;align-items:center;gap:9px;padding:8px 10px;background:#1d2b26;color:#fff}
.cwa__av{flex:none;width:30px;height:30px;border-radius:50%;background:#F5480F;color:#0a0a0a;display:grid;place-items:center;font:700 12px 'Switzer',system-ui,sans-serif}
.cwa__who{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.2}
.cwa__who b{font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cwa__stat{font-size:11px;color:#c9d3cf;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cwa__wa{flex:none;display:inline-flex;align-items:center;gap:6px;font:600 12px 'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#fff;text-decoration:none;border-radius:100px;padding:6px 11px;transition:background .15s}
.cwa__wa:hover{background:#F5480F}
.cwa__wa:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.cwa__wa svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round}
.cwa__wa-s{display:none}
@container (max-width:400px){.cwa__wa-l{display:none}.cwa__wa-s{display:inline}.cwa__stat{display:none}}
.cwa__log{flex:1;min-height:0;overflow-y:auto;padding:8px 10px;display:flex;flex-direction:column;gap:5px;background-color:#ece7df;background-image:radial-gradient(rgba(10,10,10,.06) 1px,transparent 1.2px);background-size:14px 14px;scrollbar-width:thin}
.cwa__log:focus-visible{outline:2px solid #F5480F;outline-offset:-2px}
.cwa__day{align-self:center;margin:0 0 2px;font:500 10px 'JetBrains Mono',monospace;letter-spacing:.06em;text-transform:uppercase;background:#fff;color:#4a4a4a;border-radius:4px;padding:3px 8px}
.cwa__m{position:relative;max-width:82%;padding:6px 9px 5px;border-radius:7px;font-size:13px;line-height:1.4;box-shadow:0 1px 0 rgba(10,10,10,.08);animation:cwa-in .2s ease-out}
@keyframes cwa-in{from{opacity:0;transform:translateY(4px)}}
.cwa__m p{margin:0;overflow-wrap:anywhere}
.cwa__m--them{align-self:flex-start;background:#fff;border-top-left-radius:0}
.cwa__m--me{align-self:flex-end;background:#dcefd2;border-top-right-radius:0}
.cwa__m--them::before,.cwa__m--me::before{content:'';position:absolute;top:0;width:8px;height:9px}
.cwa__m--them::before{left:-7px;background:#fff;clip-path:polygon(100% 0,0 0,100% 100%)}
.cwa__m--me::before{right:-7px;background:#dcefd2;clip-path:polygon(0 0,100% 0,0 100%)}
.cwa__m--sys{align-self:center;max-width:92%;background:#fdf5d8;font-size:12px;color:#3d3d3d;text-align:center;border-radius:6px}
.cwa__m--sys::before{display:none}
.cwa__meta{display:flex;justify-content:flex-end;align-items:center;gap:3px;margin-top:1px;font:500 10px 'JetBrains Mono',monospace;color:#5d6b64}
.cwa__tick svg{display:block;width:16px;height:9px;fill:none;stroke:#7c8781;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.cwa__tick[data-s="sent"] .cwa__t2{display:none}
.cwa__tick[data-s="read"] svg{stroke:#1f6fd1}
.cwa__typing{align-self:flex-start;display:flex;gap:4px;background:#fff;border-radius:7px;border-top-left-radius:0;padding:9px 11px}
.cwa__typing i{width:6px;height:6px;border-radius:50%;background:#8a948f;animation:cwa-dot 1.1s infinite ease-in-out}
.cwa__typing i:nth-child(2){animation-delay:.15s}.cwa__typing i:nth-child(3){animation-delay:.3s}
@keyframes cwa-dot{0%,60%,100%{transform:none;opacity:.5}30%{transform:translateY(-3px);opacity:1}}
.cwa__quick{flex:none;display:flex;flex-wrap:wrap;gap:5px;padding:6px 10px 2px;background:#ece7df}
.cwa__quick button{font:500 12px 'Switzer',system-ui,sans-serif;background:#fff;color:#0a0a0a;border:1px solid rgba(10,10,10,.2);border-radius:100px;padding:5px 10px;cursor:pointer;transition:border-color .15s,background .15s}
.cwa__quick button:hover{border-color:#0a0a0a}
.cwa__quick button:focus-visible{outline:2px solid #F5480F;outline-offset:1px}
.cwa__quick:empty{display:none}
.cwa__comp{flex:none;display:flex;align-items:flex-end;gap:6px;padding:6px 8px 8px;background:#ece7df}
.cwa__in{flex:1;min-width:0;font:400 13.5px/1.4 'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#fff;border:1px solid transparent;border-radius:18px;padding:8px 13px;resize:none;max-height:84px;overflow-y:auto;transition:border-color .15s}
@supports (field-sizing:content){.cwa__in{field-sizing:content;min-height:36px}}
.cwa__in::placeholder{color:#6f6f6f}
.cwa__in:focus-visible{outline:none;border-color:#0a0a0a}
.cwa__send{flex:none;width:36px;height:36px;border-radius:50%;border:0;background:#0a0a0a;color:#fff;display:grid;place-items:center;cursor:pointer;transition:background .15s,color .15s}
.cwa__send svg{width:15px;height:15px;fill:currentColor;transform:translateX(-1px)}
.cwa__send:hover:not(:disabled){background:#F5480F;color:#0a0a0a}
.cwa__send:disabled{background:#c7c2ba;color:#fff;cursor:not-allowed}
.cwa__send:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.cwa__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
@media (prefers-reduced-motion:reduce){.cwa *{transition:none!important;animation:none!important}.cwa__typing i{opacity:.8}}// Chatvenster in WhatsApp-stijl · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root=root.querySelector('.cwa')||root;
var sfx='-'+Math.random().toString(36).slice(2,7),inp=root.querySelector('.cwa__in');inp.id=inp.id+sfx;root.querySelector('.cwa__sr').setAttribute('for',inp.id);
var log=root.querySelector('.cwa__log'),typing=root.querySelector('.cwa__typing'),quick=root.querySelector('.cwa__quick'),form=root.querySelector('.cwa__comp'),send=root.querySelector('.cwa__send'),stat=root.querySelector('.cwa__stat'),wa=root.querySelector('.cwa__wa'),STAT=stat.textContent,queue=0;
var LBL={sent:'Verzonden',dlv:'Afgeleverd',read:'Gelezen'};
function now(){var d=new Date();return String(d.getHours()).padStart(2,'0')+':'+String(d.getMinutes()).padStart(2,'0');}
function bottom(){log.scrollTop=log.scrollHeight;}
function bubble(text,who){var m=document.createElement('div');m.className='cwa__m cwa__m--'+who;var p=document.createElement('p');p.textContent=text;m.appendChild(p);
if(who!=='sys'){var meta=document.createElement('span');meta.className='cwa__meta';meta.innerHTML='<time>'+now()+'</time>'+(who==='me'?'<span class="cwa__tick" data-s="sent" role="img" aria-label="Verzonden"><svg viewBox="0 0 18 10" aria-hidden="true"><path class="cwa__t1" d="M1 5.5l3 3 6-7"/><path class="cwa__t2" d="M7 8.5l1 0.2 6-7.2"/></svg></span>':'');m.appendChild(meta);}
log.insertBefore(m,typing);bottom();return m;}
function tick(m,s){var t=m.querySelector('.cwa__tick');if(t){t.dataset.s=s;t.setAttribute('aria-label',LBL[s]);}}
function reply(q){q=q.toLowerCase();
if(/vandaag|komen|langs/.test(q))return 'Ja, er is vanmiddag nog plek tussen 15:00 en 17:00. Zal ik je inplannen?';
if(/kost|prijs|tarief/.test(q))return 'Voorrijden plus het eerste half uur is € 89,50 inclusief btw. Onderdelen altijd pas na overleg.';
if(/open|ja\b/.test(q))return 'Dan is het waarschijnlijk de ontsteking. Ik kan vandaag tussen 15:00 en 17:00 langskomen. Schikt dat?';
if(/foto/.test(q))return 'Stuur gerust een foto van het display, dan kijk ik even mee.';
return 'Helder, ik kijk even in de planning en kom er zo bij je op terug.';}
function post(text){text=text.trim();if(!text)return;var m=bubble(text,'me');queue++;
setTimeout(function(){tick(m,'dlv');},500);
setTimeout(function(){tick(m,'read');typing.hidden=false;stat.textContent='typt…';bottom();},1200);
setTimeout(function(){queue--;if(!queue){typing.hidden=true;stat.textContent=STAT;}bubble(reply(text),'them');},2600);}
inp.addEventListener('input',function(){send.disabled=!inp.value.trim();});
inp.addEventListener('keydown',function(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();if(inp.value.trim())form.requestSubmit?form.requestSubmit():form.dispatchEvent(new Event('submit',{cancelable:true}));}});
form.addEventListener('submit',function(e){e.preventDefault();post(inp.value);inp.value='';send.disabled=true;inp.focus();});
quick.addEventListener('click',function(e){var b=e.target.closest('button');if(!b)return;post(b.textContent);var next=b.nextElementSibling||b.previousElementSibling;b.remove();if(next)next.focus();else inp.focus();});
wa.addEventListener('click',function(e){var mine=[].slice.call(log.querySelectorAll('.cwa__m--me p')).map(function(p){return p.textContent;});
var url='https://wa.me/31101234567?text='+encodeURIComponent(mine.slice(-2).join('\n'));wa.href=url;e.preventDefault();
bubble('Demo: in productie opent dit WhatsApp met je laatste berichten al ingevuld ('+url.slice(0,40)+'…).','sys');});
bottom();
}
init(document.querySelector('.jouw-container'));
Meer uit componenten
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 →