Menscheck zonder puzzel New
Calm anti-spam check under a contact form: one "I am human" checkbox, then a short check with a spinning ring and a drawn tick, no images or puzzles. Behind the scenes it looks at a hidden honeypot field and the fill-in time; in production you wire it to Cloudflare Turnstile or Friendly Captcha. With an error state (too fast, try again), aria-live messages and a send button that explains why it is still waiting.
How to use it
- Paste the HTML where the forms & inputs should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- 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'));
More forms & inputs
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →