Menscheck zonder puzzel Nieuw
Rustige controle tegen spam onder een contactformulier: één vinkje "Ik ben een mens", daarna een korte controle met een draaiend randje en een getekend vinkje, zonder plaatjes of puzzels. Achter de schermen kijk je naar een verborgen honingpot-veld en de invultijd; in productie koppel je dit aan Cloudflare Turnstile of Friendly Captcha. Met een foutstaat (te snel, opnieuw proberen), aria-live-meldingen en een verstuurknop die uitlegt waarom hij nog wacht.
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.
<!-- Menscheck zonder puzzel · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="mch"><div class="mch__in">
<form class="mch__f" novalidate>
<label class="mch__l" for="mch-m">Je vraag aan Dierenkliniek Amstelveen</label>
<textarea class="mch__t" id="mch-m" rows="2">Mijn kat eet sinds gisteren slecht, kan ze deze week nog terecht?</textarea>
<div class="mch__hp" aria-hidden="true"><label>Laat dit veld leeg<input class="mch__hpi" type="text" tabindex="-1" autocomplete="off"></label></div>
<div class="mch__box">
<label class="mch__chk"><input class="mch__in-c" type="checkbox" aria-describedby="mch-s"><span class="mch__vis" aria-hidden="true"><svg viewBox="0 0 24 24"><circle class="mch__ring" cx="12" cy="12" r="10"/><path class="mch__tick" d="M6.5 12.5l3.6 3.6 7.4-8"/></svg></span><span class="mch__txt">Ik ben een mens</span></label>
<span class="mch__s" id="mch-s" aria-live="polite">Geen puzzels, we kijken alleen of dit formulier door een mens is ingevuld.</span>
</div>
<div class="mch__foot"><button class="mch__btn" type="submit">Verstuur vraag</button><button class="mch__bot" type="button">Demo: doe alsof ik een bot ben</button></div>
<p class="mch__msg" role="status"></p>
</form>
</div></div>
</div>/* Menscheck zonder puzzel · NedDev · eigen werk. */
.mch{position:absolute;inset:0;overflow:auto;display:flex;padding:12px;box-sizing:border-box;background:#f4f3f1;font-family:'Switzer',sans-serif;color:#0a0a0a}
.mch *,.mch *::before,.mch *::after{box-sizing:border-box}
.mch__in{margin:auto;width:100%;max-width:390px;background:#fff;border:1px solid rgba(10,10,10,.12);border-radius:8px;padding:14px}
.mch__l{display:block;font-size:13px;font-weight:600;margin-bottom:4px}
.mch__t{display:block;width:100%;padding:7px 10px;font:400 13.5px/1.45 'Switzer',sans-serif;color:#0a0a0a;border:1px solid #8c8c8c;border-radius:4px;resize:none}
.mch__t:focus-visible{outline:none;border-color:#0a0a0a;box-shadow:0 0 0 3px rgba(245,72,15,.35)}
.mch__hp{position:absolute;left:-9999px;top:0;overflow:hidden}
.mch__hp input{height:32px}
.mch__box{display:flex;align-items:center;gap:12px;margin-top:10px;padding:9px 12px;border:1px solid rgba(10,10,10,.18);border-radius:4px;background:#faf9f7;transition:border-color .2s}
.mch[data-s="ok"] .mch__box{border-color:#1F7A3D}
.mch[data-s="fout"] .mch__box{border-color:#B42318}
.mch__chk{position:relative;display:flex;align-items:center;gap:10px;flex:none;min-height:28px;cursor:pointer;font-size:14px;font-weight:600}
.mch__in-c{position:absolute;left:0;top:50%;width:26px;height:26px;margin:-13px 0 0;opacity:0;cursor:pointer}
.mch__vis{position:relative;width:26px;height:26px;flex:none;border:2px solid #0a0a0a;border-radius:4px;background:#fff;transition:border-color .2s,background-color .2s}
.mch__in-c:focus-visible+.mch__vis{outline:2px solid #F5480F;outline-offset:2px}
.mch__chk:hover .mch__vis{background:#f4f3f1}
.mch__vis svg{position:absolute;left:-2px;top:-2px;width:26px;height:26px;fill:none;stroke-linecap:round;stroke-linejoin:round}
.mch__ring{stroke:#0a0a0a;stroke-width:2.2;stroke-dasharray:16 60;opacity:0;transform-origin:12px 12px}
.mch__tick{stroke:#fff;stroke-width:2.4;stroke-dasharray:18;stroke-dashoffset:18;transition:stroke-dashoffset .35s ease .05s}
.mch[data-s="bezig"] .mch__vis{border-color:transparent;background:none}
.mch[data-s="bezig"] .mch__ring{opacity:1;animation:mch-spin .8s linear infinite}
.mch[data-s="ok"] .mch__vis{border-color:#1F7A3D;background:#1F7A3D}
.mch[data-s="ok"] .mch__tick{stroke-dashoffset:0}
@keyframes mch-spin{to{transform:rotate(360deg)}}
.mch__s{flex:1;min-width:0;font-size:12px;line-height:1.4;color:#4a4a4a}
.mch[data-s="fout"] .mch__s{color:#B42318}
.mch__foot{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:10px}
.mch__btn{height:36px;padding:0 16px;border:0;border-radius:4px;background:#0a0a0a;color:#fff;font:600 13.5px 'Switzer',sans-serif;cursor:pointer;transition:background-color .15s}
.mch__btn:hover{background:#2a2a2a}
.mch__btn:active{transform:translateY(1px)}
.mch__bot{border:0;background:none;padding:4px 0;min-height:24px;font:500 12.5px 'Switzer',sans-serif;color:#4a4a4a;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.mch__btn:focus-visible,.mch__bot:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.mch__msg{margin:8px 0 0;font-size:12.5px;line-height:1.4}
.mch__msg:empty{display:none}
.mch__msg.is-bad{color:#B42318}
@media (prefers-reduced-motion:reduce){.mch *{transition:none!important}.mch[data-s="bezig"] .mch__ring{animation:none;stroke-dasharray:none;opacity:.35}}// Menscheck zonder puzzel · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.mch');if(!w)return;
var sfx='-'+Math.random().toString(36).slice(2,7);
w.querySelectorAll('[id]').forEach(function(el){el.id=el.id+sfx;});
w.querySelectorAll('[for]').forEach(function(el){el.setAttribute('for',el.getAttribute('for')+sfx);});
w.querySelectorAll('[aria-describedby]').forEach(function(el){el.setAttribute('aria-describedby',el.getAttribute('aria-describedby')+sfx);});
var c=w.querySelector('.mch__in-c'),s=w.querySelector('.mch__s'),hp=w.querySelector('.mch__hpi'),msg=w.querySelector('.mch__msg'),txt=w.querySelector('.mch__txt'),t0=Date.now(),tm;
var IDLE='Geen puzzels, we kijken alleen of dit formulier door een mens is ingevuld.';
function state(x,m){w.setAttribute('data-s',x);if(m)s.textContent=m;}
c.addEventListener('change',function(){clearTimeout(tm);msg.textContent='';
if(!c.checked){state('',IDLE);txt.textContent='Ik ben een mens';return;}
c.setAttribute('aria-busy','true');c.disabled=true;state('bezig','Even controleren...');
tm=setTimeout(function(){c.removeAttribute('aria-busy');c.disabled=false;
if(hp.value||Date.now()-t0<700){c.checked=false;state('fout','Dat ging te snel om zeker te zijn. Probeer het over een paar seconden opnieuw.');hp.value='';t0=Date.now();c.focus();return;}
state('ok','Gecontroleerd, je kunt versturen.');txt.textContent='Gecontroleerd';c.focus();},1300);});
w.querySelector('.mch__bot').addEventListener('click',function(){hp.value='http://spam.voorbeeld.nl';state('',IDLE);c.checked=false;txt.textContent='Ik ben een mens';msg.textContent='Honingpot-veld is nu gevuld, zoals een bot zou doen. Zet het vinkje om te zien wat er gebeurt.';msg.classList.remove('is-bad');});
w.querySelector('.mch__f').addEventListener('submit',function(e){e.preventDefault();
if(w.getAttribute('data-s')!=='ok'){msg.textContent='Zet eerst het vinkje bij "Ik ben een mens", daarna kun je versturen.';msg.classList.add('is-bad');c.focus();return;}
msg.classList.remove('is-bad');msg.textContent='Verstuurd. De assistente belt je vandaag voor 17:00 terug.';});
}
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 →