Uil die meekijkt bij inloggen Nieuw
Inlogscherm met een uil als mascotte: de ogen volgen de muis over de hele pagina, kijken mee terwijl je je e-mailadres typt en de uil houdt zijn vleugels voor de ogen zodra je je wachtwoord invult (bij "Toon" gluurt hij met één oog). Werkt volledig met toetsenbord, want de ogen volgen ook de focus. Voor het ouderportaal van een kinderopvang, een ledenomgeving van een sportclub of de klantlogin van een speelse webshop.
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.
<!-- Uil die meekijkt bij inloggen · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="mso">
<svg class="mso__uil" viewBox="0 0 120 132" aria-hidden="true">
<path d="M22 34 L30 9 L45 27 Z M98 34 L90 9 L75 27 Z" fill="#0a0a0a"/>
<path d="M60 18 C92 18 104 42 104 72 C104 106 86 126 60 126 C34 126 16 106 16 72 C16 42 28 18 60 18 Z" fill="#0a0a0a"/>
<ellipse cx="60" cy="100" rx="25" ry="20" fill="#2b2926"/>
<path d="M50 96 q4 4 8 0 M62 96 q4 4 8 0 M56 106 q4 4 8 0" stroke="#5a5650" stroke-width="2" fill="none" stroke-linecap="round"/>
<circle cx="42" cy="56" r="18" fill="#fff"/><circle cx="78" cy="56" r="18" fill="#fff"/>
<g transform="translate(42 56)"><g class="mso__oog"><circle r="8" fill="#0a0a0a"/><circle cx="-3" cy="-3" r="2.4" fill="#fff"/></g></g>
<g transform="translate(78 56)"><g class="mso__oog"><circle r="8" fill="#0a0a0a"/><circle cx="-3" cy="-3" r="2.4" fill="#fff"/></g></g>
<path d="M54 70 L66 70 L60 81 Z" fill="#F5480F"/>
<ellipse cx="48" cy="127" rx="7" ry="3.5" fill="#F5480F"/><ellipse cx="72" cy="127" rx="7" ry="3.5" fill="#F5480F"/>
<ellipse class="mso__vleugel mso__vleugel--l" cx="42" cy="58" rx="21" ry="17" fill="#F5480F"/>
<ellipse class="mso__vleugel mso__vleugel--r" cx="78" cy="58" rx="21" ry="17" fill="#F5480F"/>
</svg>
<form class="mso__form" novalidate>
<p class="mso__kop">Ouderportaal Het Uilennest</p>
<label class="mso__lbl" for="mso-mail">E-mailadres</label>
<input class="mso__in mso__mail" id="mso-mail" type="email" autocomplete="off" spellcheck="false" placeholder="naam@voorbeeld.nl">
<label class="mso__lbl" for="mso-ww">Wachtwoord</label>
<div class="mso__wwrij"><input class="mso__in mso__ww" id="mso-ww" type="password" autocomplete="off"><button type="button" class="mso__toon" aria-pressed="false" aria-label="Wachtwoord tonen">Toon</button></div>
<button type="submit" class="mso__knop">Inloggen</button>
<p class="mso__sr" aria-live="polite"></p>
</form>
</div>
</div>/* Uil die meekijkt bij inloggen · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.mso{width:100%;height:100%;display:flex;align-items:center;justify-content:center;gap:16px;padding:12px 16px;box-sizing:border-box;background:#f4f3f1;font-family:Switzer,sans-serif}
.mso__uil{flex:0 0 auto;width:min(30%,118px);height:auto;overflow:hidden}
.mso__oog{transition:transform .09s linear}
.mso__vleugel{transform:translateY(80px);transition:transform .3s cubic-bezier(.3,1.4,.5,1)}
.mso.is-dicht .mso__vleugel{transform:translateY(0)}
.mso.is-gluur .mso__vleugel--r{transform:translateY(17px)}
.mso.is-blij .mso__oog{transform:scaleY(.25)}
.mso.is-knipper .mso__oog{transform:scaleY(.1)}
.mso__form{flex:1 1 auto;max-width:230px;display:flex;flex-direction:column;min-width:0}
.mso__kop{margin:0 0 6px;font-size:15px;font-weight:600;color:#0a0a0a;line-height:1.2}
.mso__lbl{font-size:12px;color:#55524d;margin:4px 0 2px}
.mso__in{font:inherit;font-size:14px;height:30px;padding:0 8px;border:1px solid #c9c6c0;border-radius:4px;background:#fff;color:#0a0a0a;min-width:0;width:100%;box-sizing:border-box}
.mso__in:focus{outline:2px solid #F5480F;outline-offset:0;border-color:#F5480F}
.mso__wwrij{display:flex;gap:6px}
.mso__toon{font:inherit;font-size:13px;height:30px;padding:0 9px;border:1px solid #0a0a0a;border-radius:4px;background:#fff;color:#0a0a0a;cursor:pointer}
.mso__toon[aria-pressed="true"]{background:#0a0a0a;color:#fff}
.mso__knop{font:inherit;font-size:14px;font-weight:600;height:32px;margin-top:10px;border:0;border-radius:4px;background:#0a0a0a;color:#fff;cursor:pointer;transition:background-color .15s}
.mso__knop:hover{background:#F5480F}
.mso__toon:focus-visible,.mso__knop:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.mso__sr{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
@media (prefers-reduced-motion:reduce){.mso__oog,.mso__vleugel{transition:none}}// Uil die meekijkt bij inloggen · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie
// root = het element waarin de HTML staat
function init(root){
const w = root.querySelector('.mso'); if (!w) return;
const svg = w.querySelector('.mso__uil'), ogen = w.querySelectorAll('.mso__oog');
const mail = w.querySelector('.mso__mail'), ww = w.querySelector('.mso__ww'), toon = w.querySelector('.mso__toon');
const form = w.querySelector('.mso__form'), sr = w.querySelector('.mso__sr'), knop = w.querySelector('.mso__knop');
const rm = matchMedia('(prefers-reduced-motion: reduce)').matches;
const C = [[42, 56], [78, 56]];
let zichtbaar = true;
function kijk(px, py){
const r = svg.getBoundingClientRect(); if (!r.width) return; const s = r.width / 120;
ogen.forEach((o, i) => {
const ex = r.left + C[i][0] * s, ey = r.top + C[i][1] * s;
const dx = px - ex, dy = py - ey, d = Math.hypot(dx, dy) || 1;
const m = Math.min(7, d / (14 * s));
o.style.transform = 'translate(' + (dx / d * m).toFixed(2) + 'px,' + (dy / d * m).toFixed(2) + 'px)';
});
}
function naarVeld(inp){
const r = inp.getBoundingClientRect();
const x = r.left + Math.min(r.width - 8, 10 + inp.value.length * 7.5);
kijk(x, r.top + r.height / 2);
}
document.addEventListener('pointermove', e => {
if (!zichtbaar || w.classList.contains('is-blij')) return;
const a = document.activeElement; if (a === mail || a === ww) return;
kijk(e.clientX, e.clientY);
}, { passive: true });
function stand(){
const a = document.activeElement;
const dicht = a === ww || (a === toon && ww.value.length > 0);
const gluur = dicht && toon.getAttribute('aria-pressed') === 'true';
w.classList.toggle('is-dicht', dicht); w.classList.toggle('is-gluur', gluur);
if (a === mail || a === ww) naarVeld(a);
else if (a && w.contains(a)) { const r = a.getBoundingClientRect(); kijk(r.left + r.width / 2, r.top + r.height / 2); }
}
w.addEventListener('focusin', stand);
w.addEventListener('focusout', () => setTimeout(stand, 0));
mail.addEventListener('input', () => naarVeld(mail));
ww.addEventListener('input', () => naarVeld(ww));
toon.addEventListener('click', () => {
const op = toon.getAttribute('aria-pressed') !== 'true';
toon.setAttribute('aria-pressed', String(op)); toon.setAttribute('aria-label', op ? 'Wachtwoord verbergen' : 'Wachtwoord tonen');
toon.textContent = op ? 'Verberg' : 'Toon'; ww.type = op ? 'text' : 'password'; ww.focus(); stand();
});
form.addEventListener('submit', e => {
e.preventDefault();
if (!mail.value.includes('@')) { sr.textContent = 'Vul een e-mailadres in.'; mail.focus(); return; }
w.classList.remove('is-dicht', 'is-gluur'); w.classList.add('is-blij');
knop.textContent = 'Welkom terug'; sr.textContent = 'Demo: je bent ingelogd.';
setTimeout(() => { w.classList.remove('is-blij'); knop.textContent = 'Inloggen'; }, 2200);
});
if (!rm) {
(function knipper(){
setTimeout(() => {
if (zichtbaar && !w.classList.contains('is-dicht') && !w.classList.contains('is-blij')) {
const bewaar = [...ogen].map(o => o.style.transform);
ogen.forEach((o, i) => { o.style.transform = (bewaar[i] || '') + ' scaleY(.1)'; });
setTimeout(() => ogen.forEach((o, i) => { o.style.transform = bewaar[i]; }), 120);
}
knipper();
}, 3200 + Math.random() * 2600);
})();
}
if ('IntersectionObserver' in window) new IntersectionObserver(es => { zichtbaar = es[0].isIntersecting; }).observe(w);
}
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 →