Notification center
A home for updates with read state, grouped information, and animated disclosure.
pnpm dlx shadcn@latest add @uiarc/notification-center- A bell in the app header with an unread badge and an inbox of recent updates.
- Notifications people can mark read, expand, and dismiss in bulk.
- Use toast-stack for transient messages that should disappear.
- Use inbox-triage for a full-page inbox.
- Use badge for a count without a panel.
Installation
Add Notification center with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/notification-centerAdds the block and its local dependencies, and installs motion, lucide-react, @radix-ui/react-popover. First time? Add the @uiarc registry to components.json, or use the full URL:
Usage
Use it when updates need a persistent home instead of a brief toast. Connect read state to your data store.
import { NotificationCenter } from "@/registry/components/notification-center/notification-center"; export function HeaderBell() { return ( <NotificationCenter notifications={[ { id: "1", title: "Deploy finished", time: "2m", tone: "success" }, { id: "2", title: "Ana commented", time: "1h", actor: { name: "Ana", photo: "/ana.jpg" } }, ]} onReadChange={(item, read) => markRead(item.id, read)} onDismiss={item => dismiss(item.id)} /> );}API reference
2 parts. The first is the root.
NotificationCenter
A bell trigger with an unread badge that opens a popover of notifications with All and Unread views, expandable rows, and bulk actions.
notificationsRequiredNotificationItem[]–Initial notifications. The component keeps its own copy after mount.labelstring"Notifications"Panel heading and trigger label.onReadChange(notification: NotificationItem, read: boolean) => void–Called for each item marked read or unread, including Mark all read.onDismiss(notification: NotificationItem) => void–Called for each dismissed item, including Clear read.openboolean–Controlled open state.onOpenChange(open: boolean) => void–Called when the popover opens or closes.avoidCollisionsbooleantrueLets the popover flip or shift to stay in the viewport.NotificationItem
Item type: { id: string; title: string; description?: string; time: string; read?: boolean; tone?: "info" | "success" | "warning"; actor?: { name: string; photo: string } }. actor shows an avatar instead of a tone icon.
No props.
- EnterorSpace
- Opens the panel from the trigger, toggles a row's details, and activates actions.
- Escape
- Closes the panel and returns focus to the trigger (Radix Popover).
- Tab
- Moves through view toggles, rows, and row actions.
- The trigger's aria-label includes the unread count; the visual badge is aria-hidden.
- The summary line is aria-live polite, and outgoing text copies are aria-hidden while they fade.
- Row toggles use aria-expanded and announce unread state; view toggles use aria-pressed.
- Focus moves to the next row, or a view toggle, after an item is read, dismissed, or cleared.
- The bell tilts when open; counts roll like an odometer in the direction of change.
- Rows open and collapse their own height on a spring, and bulk actions cascade down the list in under a quarter second.
- Reduced motion replaces height, roll, and tilt with instant fades.
- The panel is min(424px, 100vw minus 24px) wide and at most min(590px, 100vh minus 24px) tall, with the list scrolling inside.
- Below 380px padding tightens, the details indent shrinks, and the Mark all read label becomes icon only.
- Titles and previews ellipsize on one line.
- The list is not virtualized and keeps its own copy of the notifications; cap what you pass in.
- The panel mounts in a portal only while open.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use in an app header for an inbox of updates. Use toast or toast-stack for transient messages and inbox-triage for a full-page inbox.
- notifications seeds internal state; sync changes back to your server through onReadChange and onDismiss rather than re-passing the array.
The full library index for assistants is at /llms.txt.