useWebNotification()
Last updated: 24/04/2026
Overview
useWebNotification surfaces Notification API ergonomics: isSupported guards environments without constructors, permission mirrors Notification.permission (or 'unsupported'), requestPermission() wraps Notification.requestPermission(), and show(title, options) instantiates new Notification when permission is granted, returning the instance or null on failure. Permission is read on each render (not stored in hook state), so after await requestPermission() trigger a local setState in your component to re-render and refresh the label; show must run in a secure context and typically after a user gesture-browsers may block unsolicited prompts.
What it accepts
- None.
What it returns
isSupported,permission,requestPermission,show- See API Reference.
Usage
Request access, then fire a notification with title and options (body, tag, etc.); bump state after permission so the UI updates (no JSON.stringify).
import { useState } from 'react'
import useWebNotification from '@dedalik/use-react/useWebNotification'
function Example() {
const { isSupported, permission, requestPermission, show } = useWebNotification()
const [, setTick] = useState(0)
return (
<div>
<h3>Notifications</h3>
{!isSupported ? (
<p>Notifications are not supported in this environment.</p>
) : (
<>
<p>
Permission: <strong>{permission}</strong>
</p>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<button
type='button'
onClick={async () => {
await requestPermission()
setTick((value) => value + 1)
}}
>
Request permission
</button>
<button
type='button'
onClick={() => {
const notification = show('Hello from use-react', {
body: 'This is the notification body.',
tag: 'use-web-notification-demo',
})
if (!notification) {
window.alert('Could not show notification (check permission).')
}
}}
>
Show notification
</button>
</div>
</>
)}
</div>
)
}
export default function Demo() {
return <Example />
}API Reference
useWebNotification
Signature: useWebNotification(): UseWebNotificationReturn
Parameters
None.
Returns
Object with:
isSupported-'Notification' in window(boolean).permission-Notification.permissionor'unsupported'.requestPermission- Async permission prompt (() => Promise<NotificationPermission | 'unsupported'>).show-(title: string, options?: NotificationOptions) => Notification | null.
Copy-paste hook
TypeScript
import { useCallback } from 'react'
export interface UseWebNotificationReturn {
isSupported: boolean
permission: NotificationPermission | 'unsupported'
requestPermission: () => Promise<NotificationPermission | 'unsupported'>
show: (title: string, options?: NotificationOptions) => Notification | null
}
/**
* Browser Notification API wrapper.
*/
export default function useWebNotification(): UseWebNotificationReturn {
const isSupported = typeof window !== 'undefined' && 'Notification' in window
const permission: NotificationPermission | 'unsupported' = isSupported ? Notification.permission : 'unsupported'
const requestPermission = useCallback(async (): Promise<NotificationPermission | 'unsupported'> => {
if (!isSupported) return 'unsupported'
return Notification.requestPermission()
}, [isSupported])
const show = useCallback(
(title: string, options?: NotificationOptions): Notification | null => {
if (!isSupported || Notification.permission !== 'granted') return null
try {
return new Notification(title, options)
} catch {
return null
}
},
[isSupported],
)
return { isSupported, permission, requestPermission, show }
}JavaScript
import { useCallback } from 'react'
export default function useWebNotification() {
const isSupported = typeof window !== 'undefined' && 'Notification' in window
const permission = isSupported ? Notification.permission : 'unsupported'
const requestPermission = useCallback(async () => {
if (!isSupported) return 'unsupported'
return Notification.requestPermission()
}, [isSupported])
const show = useCallback(
(title, options) => {
if (!isSupported || Notification.permission !== 'granted') return null
try {
return new Notification(title, options)
} catch {
return null
}
},
[isSupported],
)
return { isSupported, permission, requestPermission, show }
}