wkkkis-hooks

use-notifications (use-notifications)

A React hook for managing browser notifications with comprehensive feature detection and fallback support

v0.1.0

Usage

import { use-notifications } from "@/hooks"
1"use client"; 2 3import { 4 AlertCircleIcon, 5 BellIcon, 6 CheckCircle2Icon, 7 XCircleIcon, 8} from "lucide-react"; 9 10import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; 11import { Badge } from "@/components/ui/badge"; 12import { Button } from "@/components/ui/button"; 13import { 14 Card, 15 CardContent, 16 CardDescription, 17 CardFooter, 18 CardHeader, 19 CardTitle, 20} from "@/components/ui/card"; 21 22import { useNotifications } from "@/components/hooks/use-notifications"; 23 24export function UseNotificationsDemo() { 25 const { 26 permission, 27 requestPermission, 28 showNotification, 29 isSupported, 30 isSecureContext, 31 supportsActions, 32 supportsBadge, 33 supportsImage, 34 supportsVibrate, 35 supportsSound, 36 } = useNotifications(); 37 38 const handleRequestPermission = async () => { 39 try { 40 await requestPermission(); 41 } catch (error) { 42 console.error("Failed to request permission:", error); 43 } 44 }; 45 46 const handleShowNotification = () => { 47 showNotification("Demo Notification", { 48 body: "This is a test notification from the demo component", 49 icon: "/favicon.ico", 50 badge: "/favicon.ico", 51 image: "/favicon.ico", 52 // Actions are only supported with Service Worker 53 // actions: [ 54 // { 55 // action: 'view', 56 // title: 'View Details', 57 // }, 58 // ], 59 }); 60 }; 61 62 return ( 63 <Card className="relative max-w-2xl w-full"> 64 <CardHeader> 65 <CardTitle className="flex items-center gap-2"> 66 <BellIcon className="h-5 w-5" /> 67 useNotifications 68 </CardTitle> 69 <CardDescription> 70 This component demonstrates the use of the{" "} 71 <code>useNotifications</code> hook to manage browser notifications. 72 </CardDescription> 73 </CardHeader> 74 <CardContent className="space-y-4"> 75 <div className="space-y-2"> 76 <h3 className="font-medium">Browser Support</h3> 77 <div className="flex flex-wrap gap-2"> 78 <Badge variant={isSupported ? "default" : "destructive"}> 79 {isSupported ? "Supported" : "Not Supported"} 80 </Badge> 81 <Badge variant={isSecureContext ? "default" : "destructive"}> 82 {isSecureContext ? "Secure Context" : "Not Secure"} 83 </Badge> 84 </div> 85 </div> 86 87 <div className="space-y-2"> 88 <h3 className="font-medium">Feature Support</h3> 89 <div className="flex flex-wrap gap-2"> 90 <Badge variant={supportsActions ? "default" : "secondary"}> 91 Actions {supportsActions ? "✓" : "✗"} 92 </Badge> 93 <Badge variant={supportsBadge ? "default" : "secondary"}> 94 Badge {supportsBadge ? "✓" : "✗"} 95 </Badge> 96 <Badge variant={supportsImage ? "default" : "secondary"}> 97 Image {supportsImage ? "✓" : "✗"} 98 </Badge> 99 <Badge variant={supportsVibrate ? "default" : "secondary"}> 100 Vibrate {supportsVibrate ? "✓" : "✗"} 101 </Badge> 102 <Badge variant={supportsSound ? "default" : "secondary"}> 103 Sound {supportsSound ? "✓" : "✗"} 104 </Badge> 105 </div> 106 </div> 107 108 <div className="space-y-2"> 109 <h3 className="font-medium">Permission Status</h3> 110 <Badge 111 variant={ 112 permission === "granted" 113 ? "default" 114 : permission === "denied" 115 ? "destructive" 116 : "secondary" 117 } 118 > 119 {permission === "granted" ? ( 120 <CheckCircle2Icon className="mr-1 h-3 w-3" /> 121 ) : permission === "denied" ? ( 122 <XCircleIcon className="mr-1 h-3 w-3" /> 123 ) : ( 124 <AlertCircleIcon className="mr-1 h-3 w-3" /> 125 )} 126 {permission.charAt(0).toUpperCase() + permission.slice(1)} 127 </Badge> 128 </div> 129 130 {!isSupported && ( 131 <Alert variant="destructive"> 132 <AlertCircleIcon className="h-4 w-4" /> 133 <AlertTitle>Not Supported</AlertTitle> 134 <AlertDescription> 135 Your browser does not support the Notifications API. Consider 136 using a fallback UI notification system. 137 </AlertDescription> 138 </Alert> 139 )} 140 141 {!isSecureContext && ( 142 <Alert variant="destructive"> 143 <AlertCircleIcon className="h-4 w-4" /> 144 <AlertTitle>Not Secure</AlertTitle> 145 <AlertDescription> 146 The Notifications API requires a secure context (HTTPS). Please 147 use HTTPS to enable notifications. 148 </AlertDescription> 149 </Alert> 150 )} 151 152 {supportsActions && ( 153 <Alert variant="default"> 154 <AlertCircleIcon className="h-4 w-4" /> 155 <AlertTitle>Actions Support</AlertTitle> 156 <AlertDescription> 157 Note: Notification actions are only supported when using a Service 158 Worker. This demo uses the basic Notification API without a 159 Service Worker. 160 </AlertDescription> 161 </Alert> 162 )} 163 </CardContent> 164 <CardFooter className="flex lg:flex-row items-start flex-col gap-2"> 165 <Button 166 onClick={handleRequestPermission} 167 disabled={!isSupported || !isSecureContext} 168 > 169 Request Permission 170 </Button> 171 <Button 172 onClick={handleShowNotification} 173 disabled={ 174 !isSupported || !isSecureContext || permission !== "granted" 175 } 176 > 177 Show Notification 178 </Button> 179 </CardFooter> 180 </Card> 181 ); 182} 183

Install

npx wkkkis-hooks add use-notifications

Options

NameTypeDefaultDescription
permission'default' | 'granted' | 'denied'Current notification permission status
isSupportedbooleanWhether the browser supports the Notifications API
isSecureContextbooleanWhether the current context is secure (HTTPS)
supportsActionsbooleanWhether the browser supports notification actions
supportsBadgebooleanWhether the browser supports notification badges
supportsImagebooleanWhether the browser supports notification images
supportsVibratebooleanWhether the browser supports notification vibration
supportsSoundbooleanWhether the browser supports notification sounds
requestPermission() => Promise<NotificationPermission>Function to request notification permission
showNotification(title: string, options?: NotificationOptions) => voidFunction to show a notification
bodystringThe body text of the notification
iconstringThe URL of an icon to display in the notification
imagestringThe URL of an image to display in the notification
badgestringThe URL of an image used to represent the notification when there is not enough space
tagstringAn ID for a given notification that allows you to find, replace, or remove the notification
datavoidArbitrary data that you want to associate with the notification
requireInteractionbooleanWhether the notification should remain active until the user clicks or dismisses it
silentbooleanWhether the notification should be silent
soundstringThe URL of an audio file to play with the notification
vibratenumber | number[]A vibration pattern for devices with vibration hardware
dir'auto' | 'ltr' | 'rtl'The direction of the notification's text
langstringThe notification's language
renotifybooleanWhether the user should be notified after a new notification replaces an old one
stickybooleanWhether the notification should be sticky
timestampnumberThe time at which the notification was created
actionsArray<{action: string, title: string, icon?: string}>Actions to display in the notification
Thehook returns an object with the following properties
TheshowNotification function accepts an optional options parameter

Browser Support

  • The Notifications API is supported in most modern browsers with varying feature support:
  • Chrome: Full support
  • Firefox: Full support
  • Safari: Partial support (some features may not be available)
  • Edge: Full support
  • Opera: Full support
  • Note: The API requires a secure context (HTTPS) to work, except for localhost.

Feature Detection

  • The hook automatically detects browser support for various notification features
  • Provides boolean flags for each supported feature
  • Handles cases where certain features might not be available
  • Gracefully degrades functionality based on browser capabilities

Permission Management

  • Tracks the current permission status
  • Provides a function to request permission
  • Handles permission changes across browser tabs
  • Manages permission state persistence

Best Practices & Caveats

  • Always check for browser support before using the hook
  • Request permission only after a user interaction
  • Provide clear feedback about the notification permission status
  • Implement fallback UI notifications for unsupported browsers
  • Use appropriate icons and badges to improve notification visibility
  • Consider the user's context when showing notifications
  • Handle notification errors gracefully
  • Clean up notifications when they're no longer needed

Files in this hook

SourceDestination
files/use-notifications.tssrc/hooks/use-notifications.ts