Vize

Notification Center

Accessible, unstyled notification feed and inbox that can record toast history.

Package @vizejs/ui/notification-center
Maturity stable
Own the source vize lib pull notification-center
Requires context, controllable-state, id
Aliases notification center, inbox, activity feed, toast history, notifications
Covers WAI-ARIA Feed pattern, Mantine Notifications, Novu Inbox, Sonner toast history recipes

Usage

import { NotificationCenter, NotificationCenterRoot, NotificationCenterEmpty, NotificationCenterItem, NotificationCenterList, NotificationCenterTrigger } from "@vizejs/ui/notification-center";

Or copy the source into your project with vize lib pull notification-center (see Source Distribution).

API

NotificationCenter<Data = unknown>

Source: src/families/feedback/notification-center/notification-center-root.vue

Props

Prop Type Default Description
store NotificationStore<Data> undefined External store, for example one shared with a router guard or fed by connectNotificationSource. undefined creates a store per root.
initial readonly NotificationInput<Data>[] undefined Notifications seeded into the root-owned store.
maxLength number 100 History limit of the root-owned store.
now () => number Date.now Clock of the root-owned store; inject one for deterministic SSR.
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
label string "Notifications" Accessible name of the feed and base label of the trigger.
inline boolean false Render the feed permanently (inbox page) instead of as a disclosure.
open boolean undefined Controlled disclosure state. undefined selects uncontrolled behavior.
defaultOpen boolean false Initial disclosure state for uncontrolled use.

Events

Event Payload Description
update:open [value: boolean] Fired when the disclosure requests a controlled open value.
open-change [value: boolean, previous: boolean, nativeEvent: Event | null] Fired after any distinct open-state request.

Slots

Slot Slot props Description
default NotificationCenterSlotState Trigger, list, and empty-state children.

Exposed

Member Type Description
count —
listId —
open —
setOpen —
state —
store —
unreadCount —

NotificationCenterRoot<Data = unknown>

Source: src/families/feedback/notification-center/notification-center-root.vue

Props

Prop Type Default Description
store NotificationStore<Data> undefined External store, for example one shared with a router guard or fed by connectNotificationSource. undefined creates a store per root.
initial readonly NotificationInput<Data>[] undefined Notifications seeded into the root-owned store.
maxLength number 100 History limit of the root-owned store.
now () => number Date.now Clock of the root-owned store; inject one for deterministic SSR.
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
label string "Notifications" Accessible name of the feed and base label of the trigger.
inline boolean false Render the feed permanently (inbox page) instead of as a disclosure.
open boolean undefined Controlled disclosure state. undefined selects uncontrolled behavior.
defaultOpen boolean false Initial disclosure state for uncontrolled use.

Events

Event Payload Description
update:open [value: boolean] Fired when the disclosure requests a controlled open value.
open-change [value: boolean, previous: boolean, nativeEvent: Event | null] Fired after any distinct open-state request.

Slots

Slot Slot props Description
default NotificationCenterSlotState Trigger, list, and empty-state children.

Exposed

Member Type Description
open boolean Whether the list is shown (always true for inline centers).
state NotificationCenterState Stable state token.
unreadCount number Unread active notifications.
count number Active notifications.
store NotificationStore<Data> The store driving this center.
listId string Id of the feed element.
setOpen (value: boolean, event?: Event | null) => boolean Request an open value. Returns whether it changed.

NotificationCenterEmpty

Source: src/families/feedback/notification-center/notification-center-empty.vue

Slots

Slot Slot props Description
default — Empty-state contents, shown only while no active notification exists.

NotificationCenterItem<Data = unknown>

Source: src/families/feedback/notification-center/notification-center-item.vue

Props

Prop Type Default Description
notification (required) NotificationRecord<Data> required Notification snapshot to render.
position (required) number required One-based position in the feed (aria-posinset).
setSize (required) number required Feed size (aria-setsize); -1 when unknown.
markReadOnActivate boolean true Mark the notification read when the article itself is clicked or receives Enter.

Events

Event Payload Description
activate [notification: NotificationRecord<Data>, nativeEvent: Event] Fired when the article is activated by click or Enter.

Slots

Slot Slot props Description
default NotificationCenterItemSlotState<Data> Article contents. Put titleId/descriptionId on the visible headline and text.

Exposed

Member Type Description
element HTMLElement | null Rendered article.

NotificationCenterList

Source: src/families/feedback/notification-center/notification-center-list.vue

Props

Prop Type Default Description
busy boolean false Whether the feed is loading or inserting articles (aria-busy).
markReadOnActivate boolean true Default for rendered items: mark a notification read when its article is activated.
closeOnEscape boolean true Let Escape inside a disclosure-style feed close it and refocus the trigger.

Slots

Slot Slot props Description
item NotificationCenterListItemSlotProps Render one notification, normally with NotificationCenterItem.
default — Content after the articles, for example an empty state or a load-more button.

Exposed

Member Type Description
element HTMLElement | null Rendered feed element.
focusItem (index: number) => boolean Focus the article at a zero-based index. Returns whether it moved focus.

NotificationCenterTrigger

Source: src/families/feedback/notification-center/notification-center-trigger.vue

Props

Prop Type Default Description
disabled boolean false Remove the trigger from activation and sequential keyboard focus.
formatLabel (label: string, unreadCount: number) => string ${label}, ${count} unread when unread notifications exist, else label Build the accessible name from the root label and unread count.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before the trigger toggles the center. Call preventDefault() to keep state unchanged.

Slots

Slot Slot props Description
default NotificationCenterSlotState Trigger contents, typically an icon and an unread badge.

Exposed

Member Type Description
element HTMLButtonElement | null Rendered native button.
focus (options?: FocusOptions) => void Move focus to the trigger.

Behavior

Normative behavior for @vizejs/ui/notification-center: an SSR-safe notification history store and an APG feed inbox. It can serve as toast history by feeding it through connectNotificationSource. Every row is proven by the named test.

State x input Observable outcome Proven by
store add Notifications are frozen snapshots, newest first, with "{idPrefix}-{n}" ids and timestamps from the injected now. adds notifications newest first with generated ids and injected timestamps
store add with an existing id The notification is replaced in place. re-adding an id replaces it in place
markRead/markUnread/update/archive/remove Each reports whether anything changed; archived notifications leave the feed and the unread count. read, archive, update, and remove report whether anything changed
markAllRead Only active unread notifications change; the count is returned. markAllRead only touches active unread notifications
groups Active notifications grouped by key in first-appearance order with unread counts. groups preserve first appearance order with per-group unread counts
maxLength exceeded The oldest notifications are evicted. maxLength evicts the oldest notifications
initial, clear Seeds are sorted by createdAt; clear empties the store. initial notifications and clear
connectNotificationSource Source emissions are added until the returned function unsubscribes. connectNotificationSource feeds the store until unsubscribed
invalid option or type Throws VIZE_UI_NOTIFICATION_OPTION. invalid options and inputs throw diagnostics
disclosure trigger click The trigger toggles aria-expanded, controls the feed id, names the unread count, and the feed stops being hidden. trigger discloses the feed and announces the unread count
rendered feed role="feed" with aria-label/aria-busy; articles are focusable with aria-posinset, aria-setsize, title/description wiring, data-read, data-type, data-group; inline centers omit aria-expanded. feed renders APG articles with position, size, labels, and read state
PageDown / PageUp inside an article Focus moves to the next or previous article; at the edges focus stays and the key is not consumed. PageDown and PageUp move focus between articles
click or Enter on an article The notification is marked read and activate fires unless markReadOnActivate is false; clicks on inner controls are ignored. activating an article marks it read unless opted out
Escape inside a disclosure feed The feed closes and focus returns to the trigger. Escape closes a disclosure feed and returns focus to the trigger
custom item slot Consumers render NotificationCenterItem with typed data and receive ids plus markRead/archive/remove actions. custom item slots receive typed actions and ids
root-owned store The root creates, exposes, and injects its store; useNotificationCenter() reads it; the empty state shows when nothing remains. root owns a store, exposes it, and useNotificationCenter reads it
parts or composable outside the root Throws VIZE_UI_CONTEXT_MISSING. parts and the composable require a NotificationCenterRoot
SSR Isolated requests render byte-identical feeds with deterministic ids. renders byte-identical feed markup across isolated SSR requests
hydration The feed hydrates without warnings or node replacement. hydrates the feed without diagnostics
public types Data flows through records, slots, expose, and useNotificationCenter<Data>(); types are closed unions. src/families/feedback/notification-center/notification-center.types.test-d.ts

Components

Component State x input Outcome
notification-center-root.vue store, inline, open Creates or adopts the store, owns disclosure state, provides context and the store.
notification-center-trigger.vue click Toggles the feed and labels itself with the unread count.
notification-center-list.vue notifications, PageUp/PageDown, Esc Renders the role="feed" element and one article per active notification.
notification-center-item.vue click, Enter Renders one article with feed positions and marks it read on activation.
notification-center-empty.vue no active notifications Shows the empty-state text; hidden otherwise.

Parts And Data

Target Public contract
Root data-vize-ui="notification-center-root", part="root", data-state, data-inline, data-unread-count
Trigger data-vize-ui="notification-center-trigger", part="trigger", data-unread-count, data-has-unread
List data-vize-ui="notification-center-list", part="list", role="feed", data-count
Item data-vize-ui="notification-center-item", part="item", data-read, data-type, data-group
Empty data-vize-ui="notification-center-empty", part="empty"

The feed pattern's Control+Home / Control+End exits are left to the surrounding page. NotificationCenter ships no stylesheet.