Notifications store

notifications.mjs · <ui-statusbar> · <ui-notifications>

App-global store backing both <ui-statusbar> (the inline projection of the top active item) and <ui-notifications> (the popover with the full list). Use the components for visible UI; use this store for conditions that remain relevant, such as pending work or an unresolved problem. For one-shot announcements that disappear in a few seconds, use toast() instead.

Every item is either active or historic, and that transition runs one way. An item stays active for as long as its render(el) returns true; the first time it returns false its subscriptions are torn down, archive(el) runs, the element is frozen as a snapshot of that last render, and render is never called again. <ui-statusbar> projects only the top active item; <ui-notifications> lists both, so a state that has passed is still there for the user to read.

API

ExportSignatureDescription
notify (opts) => string Add an item or update one with the same id. Returns the id. Calling again with the same id while that item is still active replaces it in place — the element and the original timestamp are reused, so the element does not flicker and the item keeps its place in recency order. Once the item has been archived, the same call starts a fresh element and timestamp.
clear (id) => void Remove an item entirely. archive is not called. Use this when the underlying state is gone (user dismissed, page navigated away).
refresh () => void Re-evaluate every active item's render(); historic items are skipped. Use as a fallback when the data an item reads has changed but you can't wire it via events/setup. The store also runs this by itself whenever the tab returns to the foreground.
get_all () => NotificationItem[] All items, active first by severity, then historic by recency. Historic items are capped at 50 — the oldest are removed as new ones arrive.
get_active_count () => number How many items are currently active. <ui-statusbar> uses it for its count badge, which only appears when more than one item is active.
get_top_active () => NotificationItem|null The single highest-priority active item — what <ui-statusbar> projects.
get_by_id (id) => NotificationItem|null Look up by id. Used by projections to resolve action_callback from cloned DOM.
events EventTarget Dispatches 'change' whenever the store mutates. Subscribe for custom UI.
clone_for_projection (canonical) => HTMLElement Advanced. Clone the canonical <ui-notification-item> for a custom projection surface.
patch_projection (target, canonical) => void Advanced. In-place patch a projection element to match the canonical without re-mounting children.

notify options shorthand: {id, type, icon, message, value, max, action_label, action_href, action_icon, action_callback, is_current} builds a default render automatically. action_href makes the action a link and needs no callback; without it the action is a button that runs action_callback. is_current is what holds the item active — the default render returns its result, so a shorthand item that omits it archives on its first render and never reaches the statusbar. Pass your own render(el) => boolean for full control. render returning false archives the item.

Configure updates for individual items through additional notify options (distinct from the module-level events EventTarget above): events takes an array of window event names, or [target, ...names] tuples for a non-window target, and re-runs render on each; setup subscribes imperatively and returns its own cleanup; archive(el) runs once when the item becomes historic. It can adjust the final element before the store preserves it. The events and setup wiring is torn down when the item archives, is cleared, or is replaced by another notify.

Progress. Pass value to show a measured quantity as a native <progress> after the message; max defaults to 1, so a fraction can be passed on its own. Use it for one quantity that is counting up, such as bytes fetched of bytes expected. A sequence of named phases is a step tracker instead, not a bar. The bar takes the item's type color, so a warning's bar matches its warning icon.

The figure is captured when notify is called, so a figure that moves means calling notify again with the same id and the new numbers. The reactive hooks (events, setup) re-run render with the values it closed over and cannot show a changing quantity. Throttle before you call. Each upsert rebuilds the item object, tears down and re-wires its subscriptions, and makes every projection replace its children — and the statusbar's inline region is role="status", so each one also offers a screen reader a fresh announcement. Roughly once a second is enough to show that something is moving; a per-chunk callback is not.

1. notify + clear

Calling notify with the same id replaces the existing item in place. clear(id) removes it.

Show code

2. get_top_active

Returns the single highest-priority active item, sorted by severity (error > warning > info), then by recency. Useful for custom inline projections.

(none)
Show code

3. events listener

Subscribe to 'change' for live updates. Use this in custom widgets that aren't built on <ui-statusbar>/<ui-notifications>.

0 active
Show code

4. get_all inventory

Returns the full list (active + historic). Active items first, ordered by severity, then by recency.

idstatetypemessage
Show code

5. Action callback flow

Pass action_label + action_callback for an inline button. Clicking it invokes the callback (resolved via get_by_id) on the canonical item, no matter which projection the user clicked.

No retries yet
Show code