Notification Badge
refinery/notification-badgeFreeComponent
Notification Bell with animated notification badge and pop-up with various configurations.
Live preview
live · rendered by the registry
Rendered by refinery on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://refinery.abhii.me/r/notification-badge.jsonSource
1"use client";23import { cn } from "@/lib/utils";4import {5 motion,6 AnimatePresence,7 useAnimate,8 useReducedMotion,9} from "motion/react";10import type { Variants } from "motion/react";11import { useEffect, useRef, useState } from "react";12import type {13 Dispatch,14 FunctionComponent,15 MouseEventHandler,16 ReactNode,17} from "react";1819export interface NotificationItem {20 id: string | number;21 message: string;22 timestamp?: string;23 icon?: ReactNode;24 unread?: boolean;25}2627type BadgeVariant = "dot" | "count";28type NotificationId = NotificationItem["id"];2930type NotificationTriggerProps = {31 open: boolean;32 onClick: MouseEventHandler<HTMLElement>;33 unreadCount: number;34 total: number;35 items: NotificationItem[];36};3738interface NotificationBadgeProps {39 notifications?: NotificationItem[];40 badgeVariant?: BadgeVariant;41 panelTitle?: string;42 markAllReadLabel?: string | null;43 footerLabel?: string | null;44 emptyLabel?: string;45 onNotificationClick?: Dispatch<NotificationItem>;46 onDismiss?: Dispatch<NotificationItem>;47 onMarkAllRead?: () => void;48 onFooterClick?: () => void;49 trigger?: FunctionComponent<NotificationTriggerProps>;50 className?: string;51 panelClassName?: string;52}5354const panelVariants: Variants = {55 hidden: { opacity: 0, scale: 0.96, y: -6 },56 visible: {57 opacity: 1,58 scale: 1,59 y: 0,60 transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] },61 },62 exit: {63 opacity: 0,64 scale: 0.96,65 y: -6,66 transition: { duration: 0.15, ease: [0.4, 0, 1, 1], delay: 0.05 },67 },68};6970const dotVariants: Variants = {71 hidden: { scale: 0 },72 visible: {73 scale: 1,74 transition: { type: "spring", stiffness: 400, damping: 18 },75 },76 exit: {77 scale: 0,78 transition: { duration: 0.15 },79 },80};8182const bellShakeKeyFrames = [0, 14, -10, 8, -5, 3, -2, 0];8384export default function NotificationBadge({85 notifications: notificationsProp,86 badgeVariant = "dot",87 panelTitle = "Notifications",88 markAllReadLabel = "Mark all as read",89 footerLabel = "View all notifications",90 emptyLabel = "You're all caught up!",91 onNotificationClick,92 onDismiss,93 onMarkAllRead,94 onFooterClick,95 trigger,96 className,97 panelClassName,98}: NotificationBadgeProps) {99 const [open, setOpen] = useState(false);100 const [uncontrolledItems, setUncontrolledItems] = useState<101 NotificationItem[]102 >(() => notificationsProp ?? []);103 const [readIds, setReadIds] = useState<Set<NotificationId>>(() => new Set());104// … truncated
What it pulls in
npm packages
Files it writes
More from refinery
All 16 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analog Clock Screensaveranalog-clock-screensaver | refinery | Components | Free | 1 dep | |
| Avatar Circleavatar-circle | refinery | Components | Free | 1 dep | |
| DVD Screensaverdvd-screensaver | refinery | Components | Free | 1 dep | |
| Floating Cardfloating-card | refinery | Components | Free | 1 dep | |
| Floating Navfloating-nav | refinery | Components | Free | 1 dep | |
| Glowy Buttonglowy-button | refinery | Components | Free | 1 dep | |
| Move To Topmove-to-top-button | refinery | Components | Free | 1 dep | |
| Sleeping Cat Screensaversleeping-cat-screensaver | refinery | Components | Free | 2 deps |
