Chapter 53: Web Notifications API & Native Push

Building an In-App Notification Center with Desktop Fallback

**Part 11: HTML5 APIs Part 2** — Chapter 53: Notifications API

LEARNING OBJECTIVES
  • Build a production-grade dual-tier Notification Hub (In-App Toast/Badge + OS Desktop Notification).
  • Detect page visibility via document.visibilityState to route alerts intelligently (Toasts when tab is active, OS alerts when tab is hidden).
  • Manage unread counters and badge icons via the App Badging API (navigator.setAppBadge()).
  • Ensure full keyboard and screen reader accessibility with role="region" and aria-live.
🎬 INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
🌐
1. Input
Directives & Tags
⚙️
2. Parse
Tokenizer & AST
🌳
3. Layout
Box Model & Flow
🎨
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

💻 Interactive Code Playground


class NotificationCenter {
  constructor() {
    this.unreadCount = 0;
    this.badgeEl = document.getElementById('badge-counter');
  }

  notify({ title, body, icon = '/icons/alert.png', url = '/' }) {
    this.unreadCount++;
    this.updateBadges();

    // Strategy 1: Tab is in FOREGROUND -> Show In-App Toast
    if (document.visibilityState === 'visible') {
      this.showToast({ title, body });
    } 
    // Strategy 2: Tab is in BACKGROUND -> Dispatch OS Notification
    else if ('Notification' in window && Notification.permission === 'granted') {
      const notif = new Notification(title, { body, icon, tag: 'app-alert' });
      notif.onclick = () => {
        window.focus();
        notif.close();
      };
    }
  }

  showToast({ title, body }) {
    const toast = document.createElement('div');
    toast.className = 'toast-banner';
    toast.setAttribute('role', 'status');
    toast.innerHTML = `<strong>${title}</strong><p>${body}</p>`;
    document.getElementById('toast-container').appendChild(toast);
    setTimeout(() => toast.remove(), 4000);
  }

  updateBadges() {
    if (this.badgeEl) this.badgeEl.textContent = this.unreadCount;
    // Native OS PWA App Icon Badge
    if ('setAppBadge' in navigator) {
      navigator.setAppBadge(this.unreadCount).catch(console.error);
    }
  }

  clearBadges() {
    this.unreadCount = 0;
    if (this.badgeEl) this.badgeEl.textContent = '0';
    if ('clearAppBadge' in navigator) {
      navigator.clearAppBadge().catch(console.error);
    }
  }
}

📌 Key Takeaways

  • Use document.visibilityState to avoid annoying users with duplicate OS alerts when they are already looking at your active page.
  • Use navigator.setAppBadge(count) to display native unread count badges on PWA app icons in macOS Dock and Windows Taskbar.
  • --

❓ Knowledge Check

1. Which of the following is correct?

2. Which of the following is correct?