Aandacht vragen, ingetogen New
Three calm ways to ask for attention, each with a reduced-motion variant: a button that pulses softly once after 4 seconds of inactivity (and never again), a field that briefly shakes on an error after submit (with an aria-live error message), and a counter badge that bumps when an item is added. Do: once, in response to the visitor. Do not: repeat, use on several buttons at once or as fake urgency. Plain CSS keyframes; tabs with arrow keys.
Na 4 seconden stilstand pulseert de knop één keer. Wel bij één hoofdactie, niet herhalen.
Wacht op stilstand.
Alleen na versturen, nooit tijdens het typen. De tekst legt uit wat er mis is.
Een bevestiging van wat de bezoeker net deed, geen nep-urgentie.
How to use it
- Paste the HTML where the buttons 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.
<!-- Aandacht vragen, ingetogen · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="atr">
<div class="atr__tabs" role="tablist" aria-label="Soorten aandacht">
<button class="atr__tab" type="button" role="tab" id="atr-t1" aria-controls="atr-p1" aria-selected="true">Zachte puls</button>
<button class="atr__tab" type="button" role="tab" id="atr-t2" aria-controls="atr-p2" aria-selected="false" tabindex="-1">Wiebel bij fout</button>
<button class="atr__tab" type="button" role="tab" id="atr-t3" aria-controls="atr-p3" aria-selected="false" tabindex="-1">Teller</button>
</div>
<div class="atr__panel" role="tabpanel" id="atr-p1" aria-labelledby="atr-t1">
<p class="atr__note">Na 4 seconden stilstand pulseert de knop één keer. Wel bij één hoofdactie, niet herhalen.</p>
<div class="atr__row"><button class="atr__cta atr__puls" type="button">Plan een adviesgesprek</button><button class="atr__link atr__reset" type="button">Opnieuw</button></div>
<p class="atr__st" aria-live="polite">Wacht op stilstand.</p>
</div>
<div class="atr__panel" role="tabpanel" id="atr-p2" aria-labelledby="atr-t2" hidden>
<p class="atr__note">Alleen na versturen, nooit tijdens het typen. De tekst legt uit wat er mis is.</p>
<form class="atr__form" novalidate><label class="atr__lab" for="atr-pc">Postcode</label><div class="atr__row"><input class="atr__in" id="atr-pc" type="text" inputmode="text" autocomplete="postal-code" placeholder="3511 AB" aria-describedby="atr-msg"><button class="atr__cta" type="submit">Controleer</button></div>
<p class="atr__msg" id="atr-msg" aria-live="polite"></p></form>
</div>
<div class="atr__panel" role="tabpanel" id="atr-p3" aria-labelledby="atr-t3" hidden>
<p class="atr__note">Een bevestiging van wat de bezoeker net deed, geen nep-urgentie.</p>
<div class="atr__row"><span class="atr__prod">Fietsbel, messing <b>€ 14,95</b></span><button class="atr__cta atr__add" type="button">In winkelmand</button>
<a class="atr__cart" href="#aandachtstrekker-set" aria-label="Winkelmand, leeg"><svg viewBox="0 0 20 20" aria-hidden="true"><path d="M2 3h2.5l2 10h9l1.8-7H6"/><circle cx="8" cy="16.5" r="1.2"/><circle cx="14.5" cy="16.5" r="1.2"/></svg><span class="atr__badge" hidden>0</span></a><button class="atr__link atr__empty" type="button">Leegmaken</button></div>
<p class="atr__st atr__cst" aria-live="polite"></p>
</div>
</div>
</div>/* Aandacht vragen, ingetogen · NedDev · eigen werk. */
.atr{position:absolute;inset:0;display:flex;flex-direction:column;background:#fff;color:#0a0a0a;font-family:'Switzer',sans-serif;padding:12px 16px;box-sizing:border-box;text-align:left;overflow:auto;scrollbar-width:thin}
.atr *,.atr *::before,.atr *::after{box-sizing:border-box}
.atr__tabs{flex:none;display:flex;gap:16px;border-bottom:1px solid #e4e2de;margin-bottom:12px}
.atr__tab{position:relative;margin:0;padding:6px 0 9px;border:0;background:none;color:#5c5a57;font:500 13px/1.2 'Switzer',sans-serif;cursor:pointer;transition:color .16s}
.atr__tab:hover{color:#0a0a0a}
.atr__tab[aria-selected="true"]{color:#0a0a0a;font-weight:600}
.atr__tab[aria-selected="true"]::after{content:'';position:absolute;left:0;right:0;bottom:-1px;height:2px;background:#F5480F}
.atr__tab:focus-visible{outline:2px solid #F5480F;outline-offset:2px;border-radius:4px}
.atr__panel{flex:1 0 auto;display:flex;flex-direction:column;justify-content:center;gap:10px;padding-bottom:12px}
.atr__panel[hidden]{display:none}
.atr__note{margin:0;font:400 13px/1.45 'Switzer',sans-serif;color:#4a4845;max-width:34em}
.atr__row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.atr__cta{position:relative;margin:0;padding:10px 14px;border:0;border-radius:4px;background:#0a0a0a;color:#fff;font:600 13px/1 'Switzer',sans-serif;cursor:pointer;transition:background-color .16s}
.atr__cta:hover{background:#333}
.atr__cta:active{transform:translateY(1px)}
.atr__cta:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.atr__puls{background:#F5480F;color:#0a0a0a}
.atr__puls:hover{background:#ff6a36}
.atr__puls::after{content:'';position:absolute;inset:0;border-radius:4px;border:2px solid #F5480F;opacity:0;pointer-events:none}
.atr__link{margin:0;padding:4px 2px;border:0;background:none;color:#0a0a0a;font:500 13px/1.2 'Switzer',sans-serif;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.atr__link:hover{color:#b8330a}
.atr__link:focus-visible{outline:2px solid #F5480F;outline-offset:2px;border-radius:4px}
.atr__st{margin:0;font:400 12px/1.3 'Switzer',sans-serif;color:#5c5a57;min-height:1.3em}
.atr__lab{display:block;margin-bottom:4px;font:500 13px/1.2 'Switzer',sans-serif}
.atr__in{width:120px;height:36px;margin:0;padding:0 10px;border:1px solid #8a8781;border-radius:4px;font:400 14px 'Switzer',sans-serif;color:#0a0a0a;background:#fff;transition:border-color .16s}
.atr__in:hover{border-color:#0a0a0a}
.atr__in:focus-visible{outline:2px solid #F5480F;outline-offset:1px;border-color:#0a0a0a}
.atr__in[aria-invalid="true"]{border-color:#c4231b;border-width:2px}
.atr__msg{margin:6px 0 0;min-height:1.3em;font:500 12.5px/1.3 'Switzer',sans-serif}
.atr__msg.is-fout{color:#c4231b}
.atr__msg.is-ok{color:#17663a}
.atr__msg.is-fout::before{content:'! ';font-weight:700}
.atr__prod{font:400 13px/1.3 'Switzer',sans-serif}
.atr__prod b{font-weight:600;margin-left:4px}
.atr__cart{position:relative;display:grid;place-items:center;width:36px;height:36px;border:1px solid #cfccc7;border-radius:4px;color:#0a0a0a;transition:border-color .16s}
.atr__cart:hover{border-color:#0a0a0a}
.atr__cart:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.atr__cart svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round;stroke-linecap:round}
.atr__badge{position:absolute;top:-7px;right:-7px;min-width:18px;height:18px;padding:0 4px;border-radius:4px;background:#F5480F;color:#0a0a0a;font:700 11px/18px 'Switzer',sans-serif;text-align:center;font-variant-numeric:tabular-nums}
.atr__badge[hidden]{display:none}
@media (prefers-reduced-motion:no-preference){
.atr__puls.is-puls::after{animation:atr-puls 1.4s cubic-bezier(.2,.6,.3,1) 2}
.atr__in.is-wiebel{animation:atr-wiebel .36s ease-in-out}
.atr__badge.is-op{animation:atr-op .26s cubic-bezier(.3,.7,.3,1.4)}}
@media (prefers-reduced-motion:reduce){.atr__puls.is-puls::after{opacity:1;inset:-4px;border-radius:4px}}
@keyframes atr-puls{0%{opacity:.8;inset:0}100%{opacity:0;inset:-9px}}
@keyframes atr-wiebel{0%,100%{transform:none}20%{transform:translateX(-5px)}40%{transform:translateX(5px)}60%{transform:translateX(-3px)}80%{transform:translateX(2px)}}
@keyframes atr-op{0%{transform:scale(1)}50%{transform:scale(1.28)}100%{transform:scale(1)}}// Aandacht vragen, ingetogen · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.atr');if(!w)return;
var tabs=[].slice.call(w.querySelectorAll('.atr__tab'));
function sel(t,f){tabs.forEach(function(x){var on=x===t;x.setAttribute('aria-selected',on);x.tabIndex=on?0:-1;w.querySelector('#'+x.getAttribute('aria-controls')).hidden=!on;});if(f)t.focus();if(t.id==='atr-t1')arm();}
tabs.forEach(function(t,k){t.addEventListener('click',function(){sel(t);});t.addEventListener('keydown',function(e){var j=null;if(e.key==='ArrowRight')j=(k+1)%tabs.length;else if(e.key==='ArrowLeft')j=(k-1+tabs.length)%tabs.length;else if(e.key==='Home')j=0;else if(e.key==='End')j=tabs.length-1;if(j!==null){e.preventDefault();sel(tabs[j],true);}});});
var puls=w.querySelector('.atr__puls'),st=w.querySelector('#atr-p1 .atr__st'),idle=null,done=false;
function arm(){clearTimeout(idle);if(done)return;st.textContent='Wacht op stilstand.';idle=setTimeout(function(){if(w.querySelector('#atr-p1').hidden)return;puls.classList.add('is-puls');done=true;st.textContent='Eén keer gepulseerd, daarna niet meer.';},4000);}
['pointermove','keydown','wheel'].forEach(function(ev){w.addEventListener(ev,function(){if(!done)arm();},{passive:true});});
puls.addEventListener('click',function(){puls.classList.remove('is-puls');clearTimeout(idle);done=true;st.textContent='Gekozen. De knop vraagt geen aandacht meer.';});
w.querySelector('.atr__reset').addEventListener('click',function(){puls.classList.remove('is-puls');done=false;arm();});
var form=w.querySelector('.atr__form'),inp=w.querySelector('.atr__in'),msg=w.querySelector('.atr__msg');
form.addEventListener('submit',function(e){e.preventDefault();var v=inp.value.trim().toUpperCase();var ok=/^[1-9][0-9]{3} ?[A-Z]{2}$/.test(v);msg.className='atr__msg';
if(ok){inp.removeAttribute('aria-invalid');msg.classList.add('is-ok');msg.textContent='Klopt, we bezorgen in '+v.replace(/^(\d{4}) ?/,'$1 ')+'.';return;}
inp.setAttribute('aria-invalid','true');msg.classList.add('is-fout');msg.textContent=v?'Een postcode heeft 4 cijfers en 2 letters, zoals 3511 AB.':'Vul je postcode in.';
inp.classList.remove('is-wiebel');void inp.offsetWidth;inp.classList.add('is-wiebel');inp.focus();});
inp.addEventListener('animationend',function(){inp.classList.remove('is-wiebel');});
var n=0,badge=w.querySelector('.atr__badge'),cart=w.querySelector('.atr__cart'),cst=w.querySelector('.atr__cst');
function setN(k){n=k;badge.hidden=n===0;badge.textContent=n;cart.setAttribute('aria-label',n?'Winkelmand, '+n+(n===1?' artikel':' artikelen'):'Winkelmand, leeg');cst.textContent=n?n+(n===1?' artikel':' artikelen')+' in je winkelmand.':'Je winkelmand is leeg.';}
w.querySelector('.atr__add').addEventListener('click',function(){setN(n+1);badge.classList.remove('is-op');void badge.offsetWidth;badge.classList.add('is-op');});
w.querySelector('.atr__empty').addEventListener('click',function(){setN(0);});
cart.addEventListener('click',function(e){e.preventDefault();});
arm();
}
init(document.querySelector('.jouw-container'));
More buttons
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 →