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
Name | Type | Default | Description |
---|---|---|---|
permission | 'default' | 'granted' | 'denied' | — | Current notification permission status |
isSupported | boolean | — | Whether the browser supports the Notifications API |
isSecureContext | boolean | — | Whether the current context is secure (HTTPS) |
supportsActions | boolean | — | Whether the browser supports notification actions |
supportsBadge | boolean | — | Whether the browser supports notification badges |
supportsImage | boolean | — | Whether the browser supports notification images |
supportsVibrate | boolean | — | Whether the browser supports notification vibration |
supportsSound | boolean | — | Whether the browser supports notification sounds |
requestPermission | () => Promise<NotificationPermission> | — | Function to request notification permission |
showNotification | (title: string, options?: NotificationOptions) => void | — | Function to show a notification |
body | string | — | The body text of the notification |
icon | string | — | The URL of an icon to display in the notification |
image | string | — | The URL of an image to display in the notification |
badge | string | — | The URL of an image used to represent the notification when there is not enough space |
tag | string | — | An ID for a given notification that allows you to find, replace, or remove the notification |
data | void | — | Arbitrary data that you want to associate with the notification |
requireInteraction | boolean | — | Whether the notification should remain active until the user clicks or dismisses it |
silent | boolean | — | Whether the notification should be silent |
sound | string | — | The URL of an audio file to play with the notification |
vibrate | number | number[] | — | A vibration pattern for devices with vibration hardware |
dir | 'auto' | 'ltr' | 'rtl' | — | The direction of the notification's text |
lang | string | — | The notification's language |
renotify | boolean | — | Whether the user should be notified after a new notification replaces an old one |
sticky | boolean | — | Whether the notification should be sticky |
timestamp | number | — | The time at which the notification was created |
actions | Array<{action: string, title: string, icon?: string}> | — | Actions to display in the notification |
The | — | — | hook returns an object with the following properties |
The | — | — | showNotification 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
Source | Destination |
---|---|
files/use-notifications.ts | src/hooks/use-notifications.ts |