Tutorial December 8, 2025 · 10 min read

How to Add a Notification Bell to Your Web App

The notification bell is one of the most recognized UI patterns on the web. Here is how to add one to your app — from building it yourself to dropping in a ready-made solution.

Anatomy of a Notification Bell

Every notification bell you have used — in Gmail, Slack, GitHub, Linear — shares the same core components. Understanding these pieces helps you build (or evaluate) the right solution.

1. The Bell Icon

A clickable icon, typically in the app header or top navigation. It serves as the entry point to the notification system. The icon itself is straightforward — an SVG bell from any icon library works.

2. The Unread Badge

A small circle (usually red or blue) overlaid on the bell icon, showing the count of unread notifications. This is the attention-grabbing mechanism. It must update in real time as new notifications arrive and as the user reads them.

3. The Dropdown or Drawer

Clicking the bell opens a panel showing a list of notifications. Each item typically has a title, body text, timestamp, and read/unread state. The panel needs scroll behavior, empty states, and a "mark all as read" action.

4. Individual Notification Items

Each notification in the list is a clickable card. It may include an icon or avatar, the notification content, a relative timestamp ("2 minutes ago"), and visual distinction between read and unread states.

It looks simple on the surface. But as we will see, the real complexity lives behind the UI.

Building a Notification Bell From Scratch

Let us walk through what it actually takes to build a notification bell from scratch. Even a minimal implementation touches more systems than you might expect.

Backend Requirements

You need a persistent storage layer for notifications. At minimum, this means:

-- Minimal notifications table
CREATE TABLE notifications (
  id          UUID PRIMARY KEY,
  user_id     UUID NOT NULL,
  title       TEXT NOT NULL,
  body        TEXT,
  url         TEXT,
  is_read     BOOLEAN DEFAULT false,
  created_at  TIMESTAMPTZ DEFAULT NOW()
);

Then you need API endpoints: list notifications (paginated), mark one as read, mark all as read, get unread count, and create notification. That is at least five endpoints to build, test, and maintain.

Real-Time Delivery

A notification bell without real-time updates feels broken. Users expect the badge count to update instantly when a new notification arrives. This means you need WebSockets or Server-Sent Events (SSE):

// Server: broadcasting to a user's WebSocket channel
wss.on('connection', (ws, req) => {
  const userId = authenticate(req);
  connections.set(userId, ws);

  ws.on('close', () => {
    connections.delete(userId);
  });
});

// When creating a notification, push to connected user
function sendNotification(userId, notification) {
  const ws = connections.get(userId);
  if (ws) ws.send(JSON.stringify(notification));
}

This is a simplified example. In production, you also need: reconnection logic when the connection drops, authentication for WebSocket connections, handling multiple browser tabs, horizontal scaling (if you have multiple server instances, users may connect to different ones), and heartbeat/keepalive mechanisms.

Frontend State Management

On the frontend, you need to manage: the list of notifications (with pagination and infinite scroll), the unread count (synced with the backend and updated via WebSocket), optimistic updates for mark-as-read actions, and proper loading and error states.

In a React app, this typically means a context provider or state management library dedicated to notifications, a custom hook for WebSocket connection management, and a set of UI components for the bell, badge, dropdown, and notification items.

The Hidden Complexity

Beyond the basics, there are edge cases that eat engineering time:

  • What happens when a notification arrives while the dropdown is open? Does it appear at the top or wait?
  • How do you handle notification retention? Delete after 30 days? Archive?
  • How do you batch rapid-fire events? (e.g., 10 comments in 1 minute becoming "10 new comments")
  • How do you handle the badge count when the user has 100+ unread notifications? Show "99+"?
  • Accessibility: keyboard navigation, screen reader announcements for new notifications, ARIA attributes.

Altogether, a production-quality notification bell is a 2–4 week project for a full-stack developer. That is time not spent on your core product.

The Faster Path: Using Notilayer's Widget

Notilayer gives you a production-ready notification bell — icon, unread badge, dropdown inbox, and real-time delivery — with two lines of code. No backend to build, no WebSocket server to manage, no UI components to design.

Step 1: Add the Script

<script src="https://api.notilayer.com/widget/widget.js" defer></script>

Step 2: Initialize

window.Notilayer.init({
  appId: 'YOUR_APP_ID',
  userId: 'user_123',
});

That is it. The widget renders a notification bell in your app with:

  • A bell icon with real-time unread badge count
  • A dropdown inbox with notification list, timestamps, and read states
  • Mark as read (individual and all) functionality
  • Click-through navigation to notification URLs
  • Empty state for when there are no notifications
  • Accessible keyboard navigation and ARIA labels

For a deeper dive on integrating with React specifically, see our React integration guide. For other frameworks, the JavaScript SDK documentation covers vanilla JS, Vue, Svelte, and more.

Customizing the Notification Bell

A notification bell that clashes with your UI is worse than no notification bell at all. Notilayer provides several customization options to ensure the widget feels native to your app.

Position

Choose where the bell appears: top-right, top-left, bottom-right, or bottom-left. Or mount it into a specific DOM element for full control:

window.Notilayer.init({
  appId: 'YOUR_APP_ID',
  userId: 'user_123',
  selector: '#notification-bell-container',
});

Theming

Match your brand colors, border radius, and font through the theme configuration:

window.Notilayer.init({
  appId: 'YOUR_APP_ID',
  userId: 'user_123',
  theme: {
    primaryColor: '#6366f1',     // Indigo accent
    badgeColor: '#ef4444',      // Red badge
    borderRadius: '8px',        // Rounded corners
    fontFamily: 'Inter, sans-serif',
  },
});

Learn more about widget customization options in the notification bell widget documentation.

When to Build vs When to Use a Widget

Building from scratch makes sense in a few specific scenarios:

Build if...

  • Notifications are your core product feature (e.g., you are building a Slack competitor)
  • You have strict data residency requirements that prevent using third-party services
  • You need deeply custom notification UX that goes beyond standard bell/inbox patterns

Use a widget if...

  • Notifications support your product but are not the product itself
  • You want to ship in days, not weeks
  • Your team's time is better spent on core features
  • You want real-time delivery without managing WebSocket infrastructure

For most SaaS products, notifications are a supporting feature — important, but not the thing users are paying for. In that case, reaching for a ready-made widget is the pragmatic choice.

Key Takeaway

A notification bell looks simple but requires backend APIs, real-time delivery (WebSockets), frontend state management, and careful UX design. Building from scratch is a 2–4 week investment. Notilayer's widget gives you a production-ready notification bell with two lines of code, so you can focus on your actual product. The free plan covers most early-stage SaaS apps.

Related Articles

Add a Notification Bell in 5 Minutes

Drop-in widget with bell icon, unread badge, and inbox. Free to start.