Notification Badge — Free HTML CSS JS Snippet

Notification Badge · Buttons · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Count badge: top:-5px right:-5px absolute, border:2px solid #fff separation trick
99+ overflow: textContent capped at "99+" for counts above 99
Pulsing dot: @keyframes scale(1→1.3) + opacity oscillation for live alert
Status dots: bottom:1px right:1px, green/red/amber/grey for online/busy/away/offline
Nav item badge: margin-left:auto pushes to right edge of nav link
Scale-pop on update: transform scale(1.3) → reset in 150ms setTimeout
Hide at zero: badge.style.display = "none" — never show "0" badge
All badge types: single position:relative .badge-wrap wraps any element

About this UI Snippet

Notification Badge — Count Badges, Status Dots, Pulse Animation & Nav Item Badges

Screenshot of the Notification Badge snippet rendered live

Notification badges are one of the most ubiquitous UI patterns — the red number on an app icon, the green dot on a user avatar, the unread count in a sidebar nav. This snippet provides all four badge variants in one component: count badges on icon buttons, a pulsing dot badge for live alerts, status indicator dots on user avatars, and unread count badges inside navigation items.

The count badge positioning

Badges use position: absolute on a relatively positioned .badge-wrap container. The count badge sits at top: -5px, right: -5px — overlapping the icon button corner. The border: 2px solid #fff creates a white gap between the badge and the underlying element, making the badge appear to float above the button even when backgrounds differ. This border-white separation trick is the standard count badge pattern used across all major platforms.

The 99+ overflow

When count exceeds 99, badge.textContent is set to '99+'. The min-width: 18px on the badge ensures it never collapses, and padding: 0 5px gives the '99+' text room. The border-radius: 999px (pill) adapts to any text length. This overflow pattern is used by iOS, Android, and all major social platforms.

The pulsing dot badge

The .dot.pulse class applies a CSS @keyframes animation that scales the dot from 1 to 1.3 and back with opacity oscillation. This creates a "heartbeat" effect that communicates live activity — new data arriving, a user typing, or a system alert. The pulse communicates urgency without a number.

Status indicator dots

Four colours communicate four presence states: green (online), red (busy/do not disturb), amber (away), grey (offline). Each uses position: absolute at bottom: 1px, right: 1px on the avatar — placed at the bottom-right corner, the universally recognised position for status dots in chat and collaboration apps.

The scale-pop animation on update

When the count changes, a brief transform: scale(1.3) is applied, then reset. The 150ms setTimeout removes the scale. This gives users clear visual feedback that the count has changed — a pattern used in WhatsApp and iOS notification counts.',

Animating the badge in when count goes from zero to one

When count changes from 0 to 1 (badge becomes visible), add an entrance animation: badge.style.animation = "none"; badge.offsetHeight; badge.style.animation = "badgeIn 0.3s cubic-bezier(0.34,1.56,0.64,1)"; and define @keyframes badgeIn { from { transform: scale(0); } to { transform: scale(1); } }. The offsetHeight forces a reflow between clearing and resetting the animation, ensuring it triggers correctly.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than eyeballing the badge positioning offsets, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the count badge's white border is what makes it read as floating above the icon button regardless of the button's own background color, and how the update() function's scale-pop animation avoids fighting with the badge's own hide/show display toggle. The same assistant can help optimize it, for instance asking whether reusing one update() function across the count badge, the nav-item badges, and the status dots would reduce duplication, or whether the badgePulse keyframe's infinite animation should pause when the tab is backgrounded to save battery. It's also useful for extending the component: ask it to add the badge-entrance scale animation described in the FAQ for when a count goes from zero to one, wire the status dots to real presence data from a WebSocket, or add a maximum-badges-visible rule so a page with many icon buttons doesn't feel noisy. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a set of "notification badge" variants in plain HTML, CSS, and JavaScript — count badges, a pulsing alert dot, avatar status dots, and nav-item unread counts — no icon or badge library.

Requirements:
- A reusable wrapper pattern: any icon button or avatar sits inside a relatively positioned container, and a badge element is absolutely positioned inside it, so the same wrapper pattern works for every badge type.
- A numeric count badge pinned to the top-right corner of an icon button, pill-shaped (fully rounded regardless of digit count), with a solid two-pixel border in the surrounding page/card background color so it reads as separated from the button underneath rather than blended into it; when the count exceeds 99, display "99+" instead of the raw number, and when the count is exactly zero, hide the badge entirely rather than showing a "0".
- A small pulsing dot badge (no number) that continuously scales up and fades slightly using a CSS keyframe animation, to signal live/ongoing activity without a specific count.
- Avatar status dots pinned to the bottom-right corner of circular avatars, using distinct solid colors for online, busy, away, and offline states, again separated from the avatar by a border matching the background.
- An unread-count badge inside a horizontal navigation item that is pushed to the far right edge of the row (not absolutely positioned relative to an icon), with a visually distinct "urgent" color variant for high-priority counts.
- JavaScript controls (increment, decrement, clear) that update the count badge's displayed number, hide it at zero, and play a brief scale-up-then-reset "pop" animation on every change so the update is visually noticeable.

Step by step

How to Use

  1. 1
    Click + Add and − Remove to change the notification countThe badge updates with a scale-pop animation. Click Clear to hide the badge entirely when count reaches zero. Count automatically shows "99+" when it exceeds 99.
  2. 2
    Apply count badges to any buttonWrap your button in a .badge-wrap div and add a <span class="badge count">N</span> inside it. The badge positions itself top-right via absolute positioning. Change the background colour via inline style or CSS.
  3. 3
    Use status dots on user avatarsWrap the avatar in .badge-wrap and add <span class="badge status online"> (or busy/away/offline). The dot positions at bottom-right. Change the state by swapping the class name.
  4. 4
    Add nav item badgesInside any nav link, add <span class="nav-badge">8</span> at the end. It pushes to the right via margin-left: auto. Add class="nav-badge red" for critical/alert counts.
  5. 5
    Hide badge when count is zeroThe update() function sets badge.style.display = "none" when count === 0. This is the correct pattern — do not show a "0" badge, hide it entirely. Restore display when count increases.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component with count in useState, or "Tailwind" for a React + Tailwind CSS version.

Real-world uses

Common Use Cases

App navigation and header notification counters
Count badges on header icons (bell, message, cart) communicate unread counts — wire one onto the notification bell. The white border separation makes badges readable on any background colour. Update counts via WebSocket or polling and apply the scale-pop animation on each update.
Team collaboration user presence and availability
Status dots on user avatars communicate real-time presence. Green = available for collaboration, red = do not disturb (in a meeting), amber = away, grey = offline. Update status via WebSocket events from your presence system.
Sidebar navigation unread count indicators
Nav item badges show unread messages, notifications, or items requiring attention inside a sidebar nav. The badge pushes to the far right of the nav item via margin-left: auto. Red badges communicate urgent items; blue for normal unread counts.
E-commerce shopping cart item count
Cart icon badges show the number of items in the mini cart. The scale-pop animation fires on each "Add to cart" action, giving clear visual feedback. Clear the badge when the cart is emptied. The 99+ overflow handles large carts gracefully.
Study the badge border-white separation trick
The border: 2px solid #fff on count badges creates a visual gap between the badge and the button. Without it, the badge blends into the button background. This trick works on any background colour because the white border matches the card or page background.
Gaming and social leaderboard achievement badges
Use count badges for achievement counts, streak indicators, or level badges. The pulsing dot variant communicates a newly earned achievement. Stack multiple badge types (count + status) on a profile avatar for a rich presence indicator.

Got questions?

Frequently Asked Questions

The count badge has border: 2px solid #fff. This white ring appears between the badge and the button underneath. When the button has a white or light background, the white border blends with the background and makes the badge appear to float above the button. The effect also works on coloured backgrounds — the white border creates separation that makes the badge stand out regardless of what is underneath it. This is the standard technique used by iOS, Android, and virtually every web notification badge implementation.

Connect a WebSocket: const ws = new WebSocket("wss://your-server.com/notifications"); ws.onmessage = event => { const data = JSON.parse(event.data); if (data.type === "notification_count") { count = data.count; update(); } }. Call update() whenever the count changes. The scale-pop animation provides visual feedback each time a new notification arrives. For a smoother experience, update() could also show a brief toast: "New message from Alex".

In the update() function, when count goes from 0 to 1 (badge changes from display:none to visible), add an entrance animation: badge.style.animation = "none"; badge.offsetHeight; badge.style.animation = "badgeIn 0.3s cubic-bezier(0.34,1.56,0.64,1)"; with @keyframes badgeIn { from { transform: scale(0); } to { transform: scale(1); } }. The offsetHeight forces a reflow between clearing and re-setting the animation, triggering it correctly.

Click "JSX" to download. Manage count with useState(5). The badge renders conditionally: {count > 0 && <span className="badge count">{count > 99 ? "99+" : count}</span>}. For the scale-pop on change: use a useEffect that watches count and applies a CSS class for 150ms. For status dots, derive the status class from a user.status prop: className={"badge status " + user.status}.