LEARNING OBJECTIVES ⌵
- Build a production-grade dual-tier Notification Hub (In-App Toast/Badge + OS Desktop Notification).
- Detect page visibility via
document.visibilityStateto 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"andaria-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.visibilityStateto 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?