Utilities✨ Premium

Notification Badge

A red badge on a bell that pulses while something is unread, bounces with each arrival and shakes before vanishing when cleared.

JSAnimationBadge

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Kitchen display — new orders on a tab nobody is looking at — Notification Badge example 1

① Kitchen display — new orders on a tab nobody is looking at

WhenDuring the evening service at Corvadine, the chef watches the "In progress" tab. Two orders come in from the dining room: the badge on the "To prepare" tab bounces from 2 to 3 then 4, without leaving the ticket screen; when an order moves to the kitchen, it drops back to 3 with no animation.
WhyThe badge reports what is happening elsewhere: nothing covers the tickets in progress, yet a new order does not go unnoticed. The bounce only plays when the count goes up, a drop stays quiet, and the tab's spoken name becomes "To prepare 4 orders to prepare".
SettingsButton content replaced by the tab name, badge in position: static on its right, 21 px. Texts data-nbg-one and data-nbg-many set to the singular and plural of "order to prepare". Arrivals (add()) and an order moving to the kitchen (set(3)) played in a loop by the scene.
Hiring board — a new application in a column — Notification Badge example 2

② Hiring board — a new application in a column

WhenIn Embauvia's "To sort" column, a click on "+ Add" shows a new card and bounces the column badge from 2 to 3.
WhyThe rise is the direct result of an action: the bounce confirms the addition is counted, with no extra message. The screen reader announces "3 new applications".
SettingsInbox icon instead of the bell, 34 px button, 19 px badge. The scene button calls add(); for the capture the scene clicks it, then brings the column back to 2 with set(2).
Parcel locker screen — the badge empties when the parcel is collected — Notification Badge example 3

③ Parcel locker screen — the badge empties when the parcel is collected

WhenOn the Pakorel kiosk, a large parcel icon carries the "1" badge. The code is typed, "OK": the badge shakes, disappears and stays gone; "Parcel collected, door 14 is open" appears.
WhyClearing has to really clear: after clear() the badge stays hidden and only a new parcel would bring it back. The shake marks the moment the counter drops to zero.
Settings132 px icon, 44 px badge and 1.3 rem figure from the scene CSS; parcel wording in data-nbg-one. Typing the code is played by the scene, which calls clear() then set(1) to start over.

How it works

The .nbg-badge badge sits in the corner of a real .nbg-icon button (an SVG bell). The starting number is the one written in the badge (3 by default). While it is above zero, the badge breathes in a loop (nbg-pulse, 2 s, growing to 115 %).

The counter is driven by a small API set on the root: root.fx0744.add() adds 1 (or add(5)), set(12) sets a value, clear() resets to zero, pulse(false) stops the breathing, count() reads the value. A rise makes the badge bounce (0.5 s); a drop changes the figure without animation; zero makes it shake then disappear. It only comes back with a new add() or set().

The click on the bell is yours: hook it to opening your notification list, then call clear() once they have been read. Each root has its own counter: two bells on the page, or the code pasted twice, never get mixed up.

Accessibility

  • A real, named button: the bell is a <button>, reachable from the keyboard, with a visible focus ring. Its name is the hidden .nbg-sr text, kept up to date: "3 unread notifications", "No unread notifications".
  • Changes announced: each API call writes the new phrase into a role="status" region, read politely. The starting state is not announced.
  • Wording in the HTML: data-nbg-one, data-nbg-many and data-nbg-none give the singular, the plural and the zero case, in your language and vocabulary (messages, orders, parcels).
  • Reduced motion: under prefers-reduced-motion: reduce, no breathing, bounce or shake; the figure changes and the badge disappears at zero, with no delay.
  • Not colour alone: red catches the eye but the written number and the button name carry the information; nothing relies on colour.

Browser compatibility

Dependency-free JavaScript, CSS animations (transform, box-shadow) and inline SVG. Hiding text for screen readers uses clip-path: inset() (Chrome 55, Firefox 54, Safari 9.1). Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two copies driven separately, code pasted twice, add, clear that stays at zero, set, pulse(false), keyboard, touch, 390 px, reduced motion, English page, no name added to window, 0 errors.

Chrome 55+✓ Full (measured)
Firefox 54+✓ Full (measured)
Safari 10+✓ Full (measured in WebKit)
Edge 79+✓ Full (Chromium engine)
Mobile iOS 10+✓ WebKit engine, not checked on a device
Android Chrome 55+✓ Full (touch measured)

Without JavaScript, the bell and badge show with the number written in the HTML, pulsing; only the API is missing. In Safari on Mac, Tab only reaches buttons if the system keyboard option is turned on.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0744-root" data-nbg-one="unread notification" data-nbg-many="unread notifications" data-nbg-none="No unread notifications">
  <button class="nbg-icon" type="button">
    <svg class="nbg-bell" aria-hidden="true">…</svg>
    <span class="nbg-badge nbg-pulse" aria-hidden="true">3</span>
    <span class="nbg-sr">3 unread notifications</span>
  </button>
  <span class="nbg-sr nbg-live" role="status"></span>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Starting number (HTML — text of .nbg-badge) 3 Write the real value on the server; 0 starts with the badge hidden.
Drive the counter (JS — root.fx0744) — add(k), set(n), clear(), pulse(true|false), count(). For instance add() on each message received over a WebSocket.
Spoken wording (HTML — data-nbg-one, data-nbg-many, data-nbg-none) "unread notification", "unread notifications", "No unread notifications" Your interface's vocabulary and language: "unread message", "order to prepare"…
Breathing (HTML — nbg-pulse class) present Remove the class for a still badge, or call pulse(false) once read.
Icon (HTML — content of .nbg-icon) SVG bell Swap the SVG for your icon, or for text (a channel name): the badge follows the button.
Colours and size (CSS — .nbg-badge) gradient #ef4444 → #dc2626, 22 px Your brand's alert colour; enlarge min-width, height and font-size together.

FAQ

No. clear() resets to zero, the badge shakes then disappears and stays hidden. It only comes back if your code calls add() or set() with a positive number.
Write the starting value into the badge when the page is rendered, then call root.fx0744.set(n) on each answer from your server (polling, WebSocket, push notification). set only bounces when the number goes up.
Nothing by itself: it is a real button, ready for your code. The usual case: open the notification panel, then call clear() once the user has seen them.