Notification Center ported
Every update in one calm, anchored surface.
A bell-anchored panel that lists updates, with unread counts, an all/unread filter and per-row actions.
Loading demo…
Guidance
When to use
- When the product produces asynchronous updates the user should be able to catch up on.
- When updates need triage: mark read, mark all read, dismiss, clear read.
- When the count matters — the badge and the panel share one source of truth.
When not to use
- For a single, time-critical alert — use a toast or an inline banner.
- For actions that must block — use a dialog.
- When there is nothing to accumulate — a static list is simpler.
npx shadcn-svelte@latest add @arcui/notification-centerUsage
<script lang="ts">
import NotificationCenter from '$lib/components/notification-center/notification-center.svelte';
const items = [
{ id: '1', title: 'New comment', description: 'Ada replied.', time: '2m', tone: 'info' },
{ id: '2', title: 'Deploy finished', time: '1h', tone: 'success', read: true }
];
</script>
<NotificationCenter notifications={items} />Variants & Examples
Default with Status Tones
Includes unread items with info, success, and warning tones.
<NotificationCenter notifications={items} />With Avatar Actor
Shows user portrait avatar instead of generic status icon.
<NotificationCenter
notifications={[
{ id: '1', title: 'Ana commented', time: '1h', actor: { name: 'Ana', photo: '/ana.jpg' } }
]}
/>Controlled Open State
Synchronizes panel visibility externally via open and onOpenChange.
<NotificationCenter open={panelOpen} onOpenChange={(o) => panelOpen = o} {notifications} />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
notifications | NotificationItem[] | — | The update list. Captured once (ARC uses useState(initial)). |
label | string | 'Notifications' | Panel and trigger label. |
onReadChange | (item, read) => void | — | Fired when a row is marked read or unread. |
onDismiss | (item) => void | — | Fired when a row is dismissed or cleared. |
open | boolean | — | Controlled open state; omit for uncontrolled. |
onOpenChange | (open: boolean) => void | — | Open-state callback. |
avoidCollisions | boolean | true | Let the panel flip to stay in view. |
Keyboard Interactions
| Key | Action |
|---|---|
Enter / Space | Open or close the panel from the trigger. |
Escape | Close the panel. |
Tab | Move between the view switch, mark-all, rows and footer actions. |
Accessibility
- The trigger is a labelled button whose aria-label includes the unread count.
- Unread state is conveyed by a dot plus the row label (", unread"), not colour alone.
- The summary line is aria-live="polite" so the count is announced when it changes.
- Rows are role="listitem" inside a labelled role="list".
Motion
Phase 1 still-state: no animation. Phase 2 wires the badge pop, the odometer count, the view-highlight layoutId slide, the row cascade (--index), the height-morphing rows and the panel enter/exit.
Notes for AI
- `notifications` is captured on mount — later prop changes are ignored, matching ARC.
- Do not add colour-only unread signalling; keep the dot and the aria-label.
- Avatar rows require the avatar component; the tone icons are Lucide.
Source of truth: registry/components/notification-center/notification-center.tsx