Notification center
BlockA list of notifications with read state and filters.
pnpm dlx shadcn@latest add https://caliperui.site/r/notification-center.jsonWhen to use #
Use it for
- A bell menu or inbox page.
Skip it when
- Messages that need an immediate reply.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/notification-center.json
Adds its 4 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { CheckCircle2, GitPullRequest, MessageSquare, TriangleAlert, UserPlus } from "lucide-react" import { useState } from "react" import { NotificationCenter, type NotificationItem } from "@/components/ui/notification-center" const seed: NotificationItem[] = [ { id: "n1", group: "Today", title: "Maya commented on “Pricing page”", body: "Can we make the empty state feel like a next step instead of an error?", time: "4 min ago", read: false, icon: <MessageSquare /> }, { id: "n2", group: "Today", title: "Deploy to production succeeded", body: "Build 2184 finished in 1m 12s.", time: "32 min ago", read: false, icon: <CheckCircle2 /> }, { id: "n3", group: "Today", title: "Dev requested your review", body: "Add undo to bulk archive (#418)", time: "2 h ago", read: false, icon: <GitPullRequest /> }, { id: "n4", group: "Earlier", title: "Billing card expires next month", body: "Update your payment method to avoid interruptions.", time: "Yesterday", read: true, icon: <TriangleAlert /> }, { id: "n5", group: "Earlier", title: "Sam joined the workspace", time: "Mon", read: true, icon: <UserPlus /> }, ]; export function NotificationCenterDemo() { const [items, setItems] = useState(seed); const [, setLog] = useState(""); return ( <NotificationCenter notifications={items} onOpen={(id) => { setItems((l) => l.map((n) => (n.id === id ? { ...n, read: true } : n))); setLog(`Opened: ${items.find((n) => n.id === id)?.title}`); }} onRead={(id, read) => setItems((l) => l.map((n) => (n.id === id ? { ...n, read } : n)))} onReadAll={() => setItems((l) => l.map((n) => ({ ...n, read: true })))} onDismiss={(id) => setItems((l) => l.filter((n) => n.id !== id))} /> ); }
API reference #
NotificationCenter
component
Accessibility #
It exposes group and status semantics, with aria-label, aria-hidden and aria-pressed kept in step with state. Changes that matter are announced through a live region.
Keyboard and focus handling comes from Radix popover: arrow keys move through items, Enter and Space select, and Escape closes and returns focus.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.