Request notification permissions with clear value proposition. This React notification permission dialog provides explanation of notification benefits, example notification preview, enable notifications button that triggers browser prompt, skip option for users who decline, and remember choice functionality. Built with shadcn/ui Dialog, Button, Badge, and Switch components using Tailwind CSS, users understand why notifications matter before granting permission. See benefits, enable alerts, stay informed—perfect for web apps, PWAs, dashboards, or any Next.js application that benefits from push notifications and wants to maximize opt-in rates.
"use client";import { useState } from "react";import { Bell, BellRing, Check, X, MessageSquare, Calendar, TrendingUp, Shield,} from "lucide-react";import { Button } from "@/components/ui/button";import { Badge } from "@/components/ui/badge";import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger,} from "@/components/ui/dialog";import { Separator } from "@/components/ui/separator";import { cn } from "@/lib/utils";type NotificationBenefit = { icon: React.ElementType; title: string; description: string;};const benefits: NotificationBenefit[] = [ { icon: MessageSquare, title: "Instant Messages", description: "Get notified when someone sends you a message", }, { icon: Calendar, title: "Reminders", description: "Never miss important deadlines or events", }, { icon: TrendingUp, title: "Updates", description: "Stay informed about activity that matters to you", },];export const title = "React Dialog Block Notification Permission";export default function DialogNotificationPermission() { const [open, setOpen] = useState(false); const [isRequesting, setIsRequesting] = useState(false); const [permissionState, setPermissionState] = useState< "prompt" | "granted" | "denied" | null >(null); const handleEnableNotifications = async () => { setIsRequesting(true); // Simulate permission request (in real app: use Notification API) await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate granted permission setPermissionState("granted"); setIsRequesting(false); // In real app: // const permission = await Notification.requestPermission(); // setPermissionState(permission); }; const handleSkip = () => { setOpen(false); // In real app: store preference to not ask again }; const handleClose = () => { setOpen(false); setTimeout(() => { setPermissionState(null); }, 200); }; if (permissionState === "granted") { return ( <Dialog open={open} onOpenChange={setOpen}> <div className="flex min-h-[350px] items-center justify-center"> <DialogTrigger asChild> <Button variant="outline"> <Bell className="mr-2 h-4 w-4" /> Enable Notifications </Button> </DialogTrigger> </div> <DialogContent className="sm:max-w-md"> <div className="flex flex-col items-center justify-center py-8 text-center"> <div className="flex h-12 w-12 items-center justify-center rounded-full border-2 border-primary"> <Check className="h-6 w-6 text-primary" /> </div> <h3 className="mt-4 text-lg font-semibold">Notifications Enabled</h3> <p className="mt-2 text-sm text-muted-foreground"> You'll now receive notifications to stay up to date. </p> <p className="mt-4 text-xs text-muted-foreground"> You can manage your notification preferences in Settings at any time. </p> <Button onClick={handleClose} className="mt-6"> Got it </Button> </div> </DialogContent> </Dialog> ); } if (permissionState === "denied") { return ( <Dialog open={open} onOpenChange={setOpen}> <div className="flex min-h-[350px] items-center justify-center"> <DialogTrigger asChild> <Button variant="outline"> <Bell className="mr-2 h-4 w-4" /> Enable Notifications </Button> </DialogTrigger> </div> <DialogContent className="sm:max-w-md"> <div className="flex flex-col items-center justify-center py-8 text-center"> <div className="flex h-12 w-12 items-center justify-center rounded-full border"> <X className="h-6 w-6 text-muted-foreground" /> </div> <h3 className="mt-4 text-lg font-semibold">Notifications Blocked</h3> <p className="mt-2 text-sm text-muted-foreground"> You've blocked notifications in your browser settings. </p> <div className="mt-4 rounded-lg border p-4 text-left w-full"> <p className="text-sm font-medium">To enable notifications:</p> <ol className="mt-2 text-xs text-muted-foreground space-y-1 list-decimal list-inside"> <li>Click the lock icon in your browser's address bar</li> <li>Find "Notifications" in the permissions</li> <li>Change the setting to "Allow"</li> <li>Refresh this page</li> </ol> </div> <Button variant="outline" onClick={handleClose} className="mt-6"> Close </Button> </div> </DialogContent> </Dialog> ); } return ( <Dialog open={open} onOpenChange={setOpen}> <div className="flex min-h-[350px] items-center justify-center"> <DialogTrigger asChild> <Button variant="outline"> <Bell className="mr-2 h-4 w-4" /> Enable Notifications </Button> </DialogTrigger> </div> <DialogContent className="sm:max-w-md"> <DialogHeader className="text-center"> <div className="flex justify-center mb-2"> <div className="relative"> <div className="flex h-12 w-12 items-center justify-center rounded-full border-2 border-primary"> <BellRing className="h-6 w-6 text-primary" /> </div> <span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground"> 3 </span> </div> </div> <DialogTitle>Stay in the loop</DialogTitle> <DialogDescription> Enable notifications to never miss important updates </DialogDescription> </DialogHeader> <div className="space-y-4 py-4"> {/* Benefits */} <div className="space-y-3"> {benefits.map((benefit) => { const Icon = benefit.icon; return ( <div key={benefit.title} className="flex items-start gap-3 rounded-lg border p-3" > <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md border"> <Icon className="h-4 w-4" /> </div> <div> <p className="text-sm font-medium">{benefit.title}</p> <p className="text-xs text-muted-foreground"> {benefit.description} </p> </div> </div> ); })} </div> {/* Example Notification */} <div className="space-y-2"> <p className="text-xs text-muted-foreground text-center"> Example notification </p> <div className="rounded-lg border p-3 flex items-start gap-3"> <div className="h-8 w-8 rounded-md bg-primary/10 flex items-center justify-center shrink-0"> <Bell className="h-4 w-4 text-primary" /> </div> <div className="flex-1 min-w-0"> <div className="flex items-center gap-2"> <p className="text-sm font-medium">New Message</p> <Badge variant="secondary" className="text-[10px]"> now </Badge> </div> <p className="text-xs text-muted-foreground truncate"> Sarah commented on your post: "This looks great!" </p> </div> </div> </div> <Separator /> {/* Privacy Note */} <div className="flex items-start gap-2 text-xs text-muted-foreground"> <Shield className="h-4 w-4 shrink-0 mt-0.5" /> <p> We respect your privacy. You can customize or disable notifications anytime in Settings. </p> </div> </div> <div className="flex flex-col gap-2"> <Button onClick={handleEnableNotifications} disabled={isRequesting} className="w-full" > {isRequesting ? ( <> <Bell className="mr-2 h-4 w-4 animate-pulse" /> Requesting... </> ) : ( <> <Bell className="mr-2 h-4 w-4" /> Enable Notifications </> )} </Button> <Button variant="ghost" onClick={handleSkip} disabled={isRequesting} className="w-full" > Maybe later </Button> </div> </DialogContent> </Dialog> );}