Feedback · astro-ui · NotificationCenterNew

NotificationCenterJS

Bell trigger with an unread badge and a grouped notification panel.

NotificationCenter owns the bell, the unread count, and the panel that opens from it. Groups keep rows scannable by day or source, NotificationItem renders the row (optionally as a link), and the badge stays decorative because the count is already part of the trigger’s accessible name. It is a disclosure rather than a modal: Escape and outside clicks close it, and focus returns to the bell.

Features

  • Unread badge with 99+ cap, mirrored into the trigger's accessible name
  • Grouped sections with day/source headings
  • Rows as links or static cards, with media, description, and timestamp
  • Empty-state slot for the zero-notification case
  • Header action slot (mark all read, settings)
  • Escape, outside click, and focus return handled

Usage

---
import {
  NotificationCenter,
  NotificationGroup,
  NotificationItem,
} from "astro-ui";
---

<NotificationCenter count={2} title="Notifications">
  <NotificationGroup label="Today">
    <NotificationItem unread title="Deploy finished" time="2m ago" href="/deploys/412">
      Production build 412 is live.
    </NotificationItem>
    <NotificationItem title="Ada left a comment" time="1h ago">
      On the sidebar PR.
    </NotificationItem>
  </NotificationGroup>
</NotificationCenter>

Demos

Notification panel

<NotificationCenter
  count={2}
  title="Notifications"
  placement="bottom-start"
  id="dm-notif-inbox"
>
  <NotificationGroup label="Today">
    <NotificationItem unread title="Deploy finished" time="2m ago" href="/deploys/412">
      Production build 412 is live.
    </NotificationItem>
    <NotificationItem unread title="Ada left a comment" time="1h ago">
      On the sidebar pull request.
    </NotificationItem>
  </NotificationGroup>
  <NotificationGroup label="Yesterday">
    <NotificationItem title="Weekly digest" time="Yesterday" href="/digest">
      12 components shipped, 3 blocks updated.
    </NotificationItem>
  </NotificationGroup>
</NotificationCenter>

Header action and footer

<NotificationCenter
  count={12}
  title="Activity"
  placement="bottom-start"
  id="dm-notif-actions"
>
  <Menu slot="actions" triggerLabel="Notification settings" bareTrigger>
    <MenuItem>Mark all read</MenuItem>
    <MenuItem>Mute for 1 hour</MenuItem>
    <MenuSeparator/>
    <MenuItem>Notification settings</MenuItem>
  </Menu>
  <NotificationGroup label="Today">
    <NotificationItem unread title="Build 412 passed" time="3m ago"/>
  </NotificationGroup>
  <a slot="footer" href="/notifications">View all notifications</a>
</NotificationCenter>

Empty state

<NotificationCenter
  count={0}
  title="Notifications"
  placement="bottom-start"
  id="dm-notif-empty"
>
  <Empty size="sm">
    <span slot="media" aria-hidden="true">🔔</span>
    <span slot="title">You are all caught up</span>
    <span slot="description">New activity will show up here.</span>
  </Empty>
</NotificationCenter>

API

Props

PropTypeDefaultDescription
countnumber0Unread count; 0 hides the badge.
titlestring"Notifications"Panel heading.
ariaLabelstring"Notifications"Accessible name for the trigger.
placement"bottom-end" | "bottom-start""bottom-end"Panel alignment.
openbooleanfalseRender the panel open on first paint.
classstring—Merged via cn(); Tailwind classes welcome.
idstring—Element id.
ariaLabelstring—Accessible name.

Slots

SlotDescription
triggerCustom bell content (defaults to 🔔).
(default)NotificationGroup / NotificationItem children.
actionsHeader actions (Menu, button).
footerFooter link or action.

Accessibility

Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.

  • Trigger is a button with aria-haspopup="dialog" and aria-expanded
  • Panel is a named role="dialog", focused on open
  • Groups are <section> + <h3> + <ul>, so counts are announced
  • Unread rows announce "Unread" in text, not colour alone
  • Badge number is aria-hidden to avoid double announcement

FAQ

What props does NotificationItem take?

`title`, `time`, `datetime`, `unread`, `href`, `class`, `id`, plus `media` and `description` slots. With `href` the whole row becomes one link.

How do I mark notifications read?

The component is presentational: render `unread` from your own state and update it when the user acts. Because `count` is a prop, re-render (or update the trigger label) when the unread total changes.

Can it open as a side panel instead?

Yes — compose the same groups inside `Sheet side="right"` and use NotificationCenter only for the bell and count. The inner markup is the same.

Changelog

Version history mentioning NotificationCenter.

v0.1.0 — 2026-11-11
added
  • Feedback (6): Alert, Spinner, Skeleton, Toast, Banner, NotificationCenter.