Bel die schudt bij een nieuwe melding New
Notification bell for a customer portal: when a notification arrives the bell swings with a clapper that lags slightly behind, and the new number rolls into the counter. Click the bell to mark everything as read. The demo receives two notifications by itself and then only via the test button; the text is announced via aria-live. Use it in the top bar of a portal, booking area or shop account.
Je les van donderdag 14:00 is bevestigd.
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.
<!-- Bel die schudt bij een nieuwe melding · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="k7b">
<div class="k7b__app">
<div class="k7b__bar">
<span class="k7b__brand">Rijschool Noorderbaan</span>
<button class="k7b__bell" type="button" aria-label="Meldingen, 2 ongelezen">
<span class="k7b__swing"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3.2v1.3M6.5 16.5V11a5.5 5.5 0 0 1 11 0v5.5l1.6 2H4.9z" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"/><g class="k7b__clap"><path d="M10 20.4a2 2 0 0 0 4 0" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></g></svg></span>
<span class="k7b__count" aria-hidden="true"><span class="k7b__n">2</span></span>
</button>
</div>
<div class="k7b__body">
<p class="k7b__msg" aria-live="polite">Je les van donderdag 14:00 is bevestigd.</p>
<button class="k7b__test" type="button">Stuur een testmelding</button>
</div>
</div>
</div>
</div>/* Bel die schudt bij een nieuwe melding · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.k7b{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;box-sizing:border-box;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;text-align:left;padding:12px}
.k7b *{box-sizing:border-box}
.k7b__app{width:100%;max-width:340px;background:#fff;border:1px solid rgba(10,10,10,.14);border-radius:8px;overflow:hidden}
.k7b__bar{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 8px 6px 14px;border-bottom:1px solid rgba(10,10,10,.1)}
.k7b__brand{font-weight:700;font-size:14px}
.k7b__bell{position:relative;width:44px;height:44px;display:grid;place-items:center;padding:0;border:0;border-radius:4px;background:none;color:#0a0a0a;cursor:pointer;transition:background-color .15s}
.k7b__bell:hover{background:#f4f3f1}
.k7b__bell:focus-visible{outline:2px solid #F5480F;outline-offset:1px}
.k7b__swing{position:relative;display:block;width:24px;height:24px;transform-origin:50% 3px}
.k7b__swing svg{display:block;width:24px;height:24px;overflow:visible}
.k7b__bell.is-ring .k7b__swing{animation:k7b-swing 1s cubic-bezier(.3,.6,.4,1)}
.k7b__bell.is-ring .k7b__clap{animation:k7b-clap 1s cubic-bezier(.3,.6,.4,1)}
@keyframes k7b-swing{0%{transform:rotate(0)}12%{transform:rotate(18deg)}28%{transform:rotate(-15deg)}44%{transform:rotate(10deg)}60%{transform:rotate(-6deg)}76%{transform:rotate(3deg)}100%{transform:rotate(0)}}
@keyframes k7b-clap{0%{transform:translateX(0)}18%{transform:translateX(-3px)}34%{transform:translateX(3px)}50%{transform:translateX(-2px)}66%{transform:translateX(1.5px)}100%{transform:translateX(0)}}
.k7b__count{position:absolute;top:4px;right:3px;min-width:19px;height:19px;padding:0 4px;border-radius:4px;background:#F5480F;color:#0a0a0a;font:700 12px/19px 'Switzer',system-ui,sans-serif;text-align:center;overflow:hidden;transition:transform .25s cubic-bezier(.3,1.4,.5,1),opacity .2s}
.k7b__count.is-off{transform:scale(0);opacity:0}
.k7b__count.is-pop{animation:k7b-pop .45s}
.k7b__n{display:block}
.k7b__n.is-in{animation:k7b-in .35s ease-out}
@keyframes k7b-pop{40%{transform:scale(1.3)}}
@keyframes k7b-in{from{transform:translateY(100%)}to{transform:none}}
.k7b__body{padding:12px 14px 14px}
.k7b__msg{margin:0 0 12px;min-height:38px;font-size:13px;line-height:1.45}
.k7b__msg.is-new{animation:k7b-msg .5s ease-out}
@keyframes k7b-msg{from{opacity:0;transform:translateY(6px)}}
.k7b__test{height:32px;padding:0 12px;border:1px solid #0a0a0a;border-radius:4px;background:#fff;color:#0a0a0a;font:500 13px/1 'Switzer',system-ui,sans-serif;cursor:pointer;transition:background-color .15s}
.k7b__test:hover{background:#f4f3f1}
.k7b__test:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.k7b__bell.is-ring .k7b__swing,.k7b__bell.is-ring .k7b__clap,.k7b__count.is-pop,.k7b__n.is-in,.k7b__msg.is-new{animation:none}.k7b__count{transition:none}}// Bel die schudt bij een nieuwe melding · © 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){
var w = root.querySelector('.k7b'); if (!w) return;
var bell = w.querySelector('.k7b__bell'), cnt = w.querySelector('.k7b__count'), msg = w.querySelector('.k7b__msg'), test = w.querySelector('.k7b__test');
var M = ['Nieuwe lesdatum: dinsdag 9:30, ophalen bij station Europapark.', 'Je theorie-examen staat op woensdag 12 november.', 'Kees heeft je les afgerond en een tip voor je klaargezet.', 'Betaling van € 62,50 ontvangen. Bedankt.'];
var n = 2, i = 0, auto = 0, ti = null;
function redo(el, c) { el.classList.remove(c); void el.offsetWidth; el.classList.add(c); }
function setN() {
bell.setAttribute('aria-label', n ? 'Meldingen, ' + n + ' ongelezen' : 'Meldingen, geen ongelezen');
cnt.classList.toggle('is-off', !n);
if (n) { cnt.innerHTML = '<span class="k7b__n is-in">' + (n > 9 ? '9+' : n) + '</span>'; }
}
function nieuw() {
n++; setN(); redo(cnt, 'is-pop'); redo(bell, 'is-ring');
msg.textContent = M[i++ % M.length]; redo(msg, 'is-new');
}
bell.addEventListener('click', function () {
if (!n) { msg.textContent = 'Geen nieuwe meldingen.'; return; }
n = 0; setN(); msg.textContent = 'Alles gelezen. Nieuwe meldingen zie je hier meteen.';
});
test.addEventListener('click', nieuw);
if ('IntersectionObserver' in window) {
new IntersectionObserver(function (es) {
es.forEach(function (e) {
if (e.isIntersecting && !ti && auto < 2) {
ti = setInterval(function () { auto++; nieuw(); if (auto >= 2) { clearInterval(ti); ti = null; } }, 4500);
} else if (!e.isIntersecting && ti) { clearInterval(ti); ti = null; }
});
}, { threshold: .4 }).observe(w);
}
}
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 →