Notification Triage Panel
A notification center panel grouped by date or source, with unread/all tabs and collapsible groups; on a bulk clear the items sweep out in sequence and the group height springs closed behind them.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add notification-triage-panel.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<NotificationTriagePanel/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/notification-triage-panel.en.jsonOr, once registries are configured in components.json, install it as @webberui/notification-triage-panel.
Usage
import {
NotificationTriagePanel,
type TriageNotification,
} from "@/components/ui/notification-triage-panel";
const notifications: TriageNotification[] = [
{
id: "1",
title: "Aria mentioned you",
description: "Replied to your comment in the thread.",
source: "Slack",
accent: "violet",
timestamp: Date.now() - 4 * 60_000,
},
{
id: "2",
title: "PR #482 is waiting for your review",
source: "GitHub",
accent: "green",
read: true,
timestamp: Date.now() - 42 * 60_000,
},
];
export function Example() {
const [items, setItems] = React.useState(notifications);
return (
<NotificationTriagePanel
notifications={items}
onNotificationsChange={setItems}
groupBy="date"
/>
);
}Without notifications, use defaultNotifications to enter uncontrolled mode, where the component manages the cleared and read states itself.
Props
NotificationTriagePanel
| Prop | Type | Default | Description |
|---|---|---|---|
notifications | TriageNotification[] | — | Notification list in controlled mode; pair it with onNotificationsChange |
defaultNotifications | TriageNotification[] | [] | Initial notification list in uncontrolled mode |
onNotificationsChange | (next: TriageNotification[]) => void | — | Callback for clearing or marking as read |
groupBy | "date" | "source" | "date" | What to group by |
tab | "unread" | "all" | — | Current tab in controlled mode |
defaultTab | "unread" | "all" | "unread" | Initial tab in uncontrolled mode |
onTabChange | (tab: "unread" | "all") => void | — | Callback for switching tabs |
title | React.ReactNode | "Notifications" | Panel title |
relativeTime | boolean | true | Show relative time; when off, shows HH:MM |
locale | string | — | Locale for time formatting (BCP 47) |
emptyState | React.ReactNode | — | What to show when the list is empty |
TriageNotification
| Field | Type | Description |
|---|---|---|
id | string | Stable unique identifier; the animation matches before and after states by it |
title | React.ReactNode | Primary title |
description | React.ReactNode | Secondary description text |
source | string | Source name; the grouping key when groupBy="source" |
icon | React.ReactNode | Icon on the left; a bell by default |
timestamp | Date | number | string | Event time; the grouping key when groupBy="date" |
read | boolean | Whether it has been read |
accent | "neutral" | "blue" | "green" | "amber" | "red" | "violet" | Accent color of the icon's base |
How the animation works
- Sequenced sweep-out: on a bulk clear (a whole group, or "clear all") the items slide out to the right in display order with a stagger; only after they have left does the height spring closed, and the items below flow up into the gap.
- Group collapse and backfill: once a whole group is empty, the group block itself springs its height closed and the groups below rise naturally to fill in. Clicking a group header collapses or expands it, with the content height using the same spring transition.
- One at a time: clicking an item marks it as read (in the unread tab it fades out and collapses); on hover or focus a clear button appears on the right, and clearing a single item sweeps out the same way.
- Tuning points: both the collapse spring and the sweep duration can be influenced through tokens such as
var(--wb-duration-fast,200ms), which also drive the transition colors.
Accessibility
- The panel is a
role="region", the tab strip arole="tablist", and the tab buttons carryaria-selectedand support←→to switch. - Group header buttons carry
aria-expandedandaria-controls, so collapsing works from the keyboard. - The body of each notification is a button (mark as read) and the clear button is separate with its own
aria-label, avoiding nested interactive elements. - When the user has "reduce motion" enabled at the system level, the sweep offsets and springs are replaced by a brief fade in / fade out, with no effect on how it is operated.
Setup Checklist Rail
An onboarding checklist pinned to the side of the app — completed items check off and collapse, the progress ring at the top counts up, and once everything is done it shrinks into an expandable floating badge.
Miller Column Browser
A Finder-style Miller-column hierarchy browser: every level you descend springs a new column in from the right, the whole row pans smoothly once it overflows, and breadcrumbs highlight the current path in step.