LEARNING OBJECTIVES ⌵
- Implement interactive notification buttons using the
actionsarray. - Handle action callbacks inside the
notificationclickservice worker event. - Add inline text input replies (supported on mobile Android / Chrome).
- Provide accessible fallbacks for desktop environments that do not display action buttons.
🎬 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.
📖 The Mental Model & Story
Imagine receiving a text message on your smartwatch. Instead of pulling your phone out of your pocket, unlocking it, opening the messaging app, and navigating to the chat, you can simply tap a quick button ("Accept", "Archive", or "Reply") directly on the watch face.
Notification action buttons empower users to complete transactional workflows (accept meeting, snooze alarm, approve pull request) with zero context switching.
+-------------------------------------------------------------+
| 🔔 GitPlatform: Pull Request #402 Assigned to You |
| "feat: migrate to native Popover API and Top Layer" |
| |
| [ 👍 Approve PR ] [ 💬 Request Changes ] [ Dismiss ]|
+-------------------------------------------------------------+
Technical Deep Dive & Specifications
// Register notification with action buttons
self.registration.showNotification('Calendar Invite', {
body: 'Architecture Review with Principal Engineers in 10 mins',
icon: '/images/cal.png',
actions: [
{ action: 'accept', title: '✅ Accept', icon: '/images/check.png' },
{ action: 'decline', title: '❌ Decline', icon: '/images/cross.png' }
],
data: { meetingId: '109283' }
});
// Handling specific actions in sw.js
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.action === 'accept') {
// Send API request in background without opening tab
event.waitUntil(
fetch(`/api/meetings/${event.notification.data.meetingId}/respond`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'ACCEPTED' })
})
);
} else if (event.action === 'decline') {
event.waitUntil(
fetch(`/api/meetings/${event.notification.data.meetingId}/respond`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'DECLINED' })
})
);
} else {
// User clicked the notification body itself -> Open dashboard
event.waitUntil(clients.openWindow('/calendar'));
}
});
📌 Key Takeaways
- Maximum 2–3 action buttons are supported across OS notifications.
- Actions can trigger background REST API calls using
fetch()without bringing up a browser window. - Always provide a fallback click behavior for when users click the notification body itself.
- --
❓ Knowledge Check
1. Which of the following is correct?
2. Which of the following is correct?
🏋️ Study Exercise
Task: Review the javascript example above. Identify the key directives and their purpose, then try writing your own version from memory.
// Register notification with action buttons
self.registration.showNotification('Calendar Invite', {
body: 'Architecture Review with Principal Engineers in 10 mins',
icon: '/images/cal.png',
actions: [
{ action: 'accept', title: '✅ Accept', icon: '/images/check.png' },
{ action: 'decline', title: '❌ Decline', icon: '/images/cross.png' }
],
data: { meetingId: '109283' }
});
// Handling specific actions in sw.js
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.action === 'accept') {
// Send API request in background without opening tab
event.waitUntil(
fetch(`/api/meetings/${event.notification.data.meetingId}/respond`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'ACCEPTED' })
})
);
} else if (event.action === 'decline') {
event.waitUntil(
fetch(`/api/meetings/${event.notification.data.meetingId}/respond`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'DECLINED' })
})
);
} else {
// User clicked the notification body itself -> Open dashboard
event.waitUntil(clients.openWindow('/calendar'));
}
});