Реалізація Notifications API на сайті
Push-сповіщення у браузері без мобільного додатку. Користувач дозволив — отримує сповіщення навіть коли вкладка закрита (при наявності Service Worker). Користувач не дозволив — працюємо з fallback у UI.
Notifications API та Push API — різні речі. Notifications API показує сповіщення через браузер. Push API доставляє подію з сервера. Для сповіщень при закритій вкладці потрібні обидва.
Запит дозволу
Головне правило — запрашувати дозвіл тільки після явної дії користувача, інакше браузер автоматично блокує:
async function requestNotificationPermission(): Promise<NotificationPermission> {
if (!('Notification' in window)) {
throw new Error('Notifications API не підтримується')
}
if (Notification.permission === 'granted') return 'granted'
if (Notification.permission === 'denied') return 'denied'
// Викликаємо тільки з обробника події (click, submit і т.д.)
return Notification.requestPermission()
}
Показ сповіщення
interface NotificationOptions {
title: string
body?: string
icon?: string
badge?: string
tag?: string // Групування — нове сповіщення замінить старе з тим же tag
requireInteraction?: boolean // Не закривати автоматично
data?: unknown
actions?: NotificationAction[] // Кнопки (тільки Service Worker)
}
function showNotification(options: NotificationOptions): Notification | null {
if (Notification.permission !== 'granted') return null
const { title, ...rest } = options
const notification = new Notification(title, rest)
notification.onclick = (event) => {
event.preventDefault()
window.focus()
notification.close()
// Перехід до потрібного розділу за notification.data
}
return notification
}
Сповіщення через Service Worker
Для сповіщень при закритій вкладці — тільки через SW:
// service-worker.ts
self.addEventListener('push', (event: PushEvent) => {
const data = event.data?.json() ?? {}
event.waitUntil(
self.registration.showNotification(data.title ?? 'Нове сповіщення', {
body: data.body,
icon: '/icons/notification-icon-192.png',
badge: '/icons/badge-72.png',
tag: data.tag ?? 'default',
data: { url: data.url },
actions: [
{ action: 'open', title: 'Відкрити' },
{ action: 'dismiss', title: 'Закрити' },
],
})
)
})
self.addEventListener('notificationclick', (event: NotificationEvent) => {
event.notification.close()
if (event.action === 'dismiss') return
const url = event.notification.data?.url ?? '/'
event.waitUntil(
clients.matchAll({ type: 'window' }).then((windowClients) => {
const existingClient = windowClients.find((c) => c.url === url)
if (existingClient) return existingClient.focus()
return clients.openWindow(url)
})
)
})
React-хук
function useNotifications() {
const [permission, setPermission] = useState<NotificationPermission>(
typeof Notification !== 'undefined' ? Notification.permission : 'denied'
)
const [supported] = useState(() => 'Notification' in window)
const request = useCallback(async () => {
if (!supported) return
const result = await requestNotificationPermission()
setPermission(result)
}, [supported])
const notify = useCallback(
(options: NotificationOptions) => {
if (permission !== 'granted') return null
return showNotification(options)
},
[permission]
)
return { supported, permission, request, notify }
}
Обробка станів дозволу в UI
function NotificationSettings() {
const { supported, permission, request, notify } = useNotifications()
if (!supported) {
return <p>Сповіщення не підтримуються вашим браузером</p>
}
return (
<div>
{permission === 'default' && (
<button onClick={request}>Включити сповіщення</button>
)}
{permission === 'granted' && (
<button onClick={() => notify({ title: 'Тест', body: 'Сповіщення працюють' })}>
Перевірити
</button>
)}
{permission === 'denied' && (
<p>Сповіщення заблоковані. Дозвольте у настройках браузера.</p>
)}
</div>
)
}
Що входить у роботу
Реалізація утилітів запиту дозволів та показу сповіщень, React-хук, обробка всіх станів (default, granted, denied), опціонально — інтеграція з Service Worker для Push API та VAPID-ключами на бекенді.
Строк: 0.5–1 день (без Push API). З Push API та настройкою бекенду — 1–2 дні.







