Notification Center
Preview: Default
Bell button with unread count, opening a popover list of notifications (GridList: arrow keys, Enter to open).
Import
import { NotificationCenter } from '@marbleui/ui'Props
<NotificationCenter>
| Prop | Type | Default | Description |
|---|---|---|---|
| items *required | NotificationItem[] | — | |
| emptyText | string | "You're all caught up" | |
| onMarkAllRead | () => void | — | |
| onOpenItem | (id: string) => void | — |
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria DialogTrigger · React Aria Dialog · React Aria GridList · React Aria GridListItem. Follow the primitive's docs for the full keyboard map.
Usage notes
Bell button with an unread badge that opens a popover list of notifications. For transient messages use toast; for a full page of activity use ListView.
<NotificationCenter
items={items}
onMarkAllRead={markAllRead}
onOpenItem={(id) => openNotification(id)}
/>
itemsis controlled data:{ id, title, time, body?, read?, avatar? }. You updatereadyourself inonMarkAllReadandonOpenItem.- The button’s
aria-labelincludes the unread count, and the badge caps at “9+”. “Mark all read” appears only when there are unread items andonMarkAllReadis set. - The list is a grid list: arrow keys move between items and Enter triggers
onOpenItem. emptyTextcustomises the empty message (default “You’re all caught up”).
Example source · show· hide
import { useState } from 'react'
import { Avatar } from '../avatar'
import { NotificationCenter, type NotificationItem } from './notification-center'
const initial: NotificationItem[] = [
{ id: '1', title: 'Maya Chen mentioned you', body: '“@you can you review the new pricing table before Friday?”', time: '2m ago', avatar: <Avatar size="sm" name="Maya Chen" /> },
{ id: '2', title: 'Deploy succeeded', body: 'website · production · 41s', time: '18m ago', avatar: <Avatar size="sm" name="CI" shape="square" /> },
{ id: '3', title: 'Charles Webb assigned ACME-142 to you', time: '1h ago', read: true, avatar: <Avatar size="sm" name="Charles Webb" /> },
{ id: '4', title: 'Invoice paid', body: 'INV-1042 · $1,280.00', time: 'Yesterday', read: true, avatar: <Avatar size="sm" name="Billing" shape="square" /> },
]
function Demo() {
const [items, setItems] = useState(initial)
return (
<div className="flex h-96 items-start">
<NotificationCenter
items={items}
onMarkAllRead={() => setItems(items.map((i) => ({ ...i, read: true })))}
onOpenItem={(id) => setItems(items.map((i) => (i.id === id ? { ...i, read: true } : i)))}
/>
</div>
)
}
export const styles = { Default: Demo, Empty: () => <div className="flex h-64 items-start"><NotificationCenter items={[]} /></div> }Source: packages/ui/src/notification-center/notification-center.tsx
Catalog
- Category
- feedback
- Priority
- Core
- Primitive
- composed
- React Aria
- GridList + Popover