Notification
Feedback

Notification

Persistent notification row and inbox panel. Items accumulate until read or dismissed.

Component behavior

Notification displays an inbox entry with read state and actions. The application supplies notification history and persistence.

Use cases
  • Events retained for later review — deploys, approvals, failures.
  • Messages collected in a persistent inbox.
  • Messages with read and unread state.
Alternatives

Toast: feedback reports a recent action and does not need to persist.

Banner: a condition persists across the page.

ActivityFeed: the view displays a chronological history.

NotificationItem

NotificationItem shape props
PropTypeDefaultDescription
idstring—Unique identifier.
titleReactNode—Notification title.
bodyReactNode—One or two lines of detail.
timeDate—Timestamp rendered as relative time.
readboolean—Read state. Unread rows display an indicator.
toneNotificationTone"default""default" | "info" | "ok" | "warn" | "err".
iconReactNode—Leading avatar or service icon.
categorystring—Grouping key for InboxPanel sections.
actionsNotificationAction[]—Row actions with label, onClick, and optional variant.

NotificationAction

Row actions use small Button components and default to the outline variant. Set an explicit variant for a different visual priority.

NotificationAction shape props
PropTypeDefaultDescription
labelstring—Button label.
onClick() => void—Handles action presses without calling the row onClick handler.
variantButtonVariant"outline"Button visual variant.

Notification Props

NotificationProps props
PropTypeDefaultDescription
itemNotificationItem—The notification data to render.
onRead(id: string) => void—Mark as read handler.
onDismiss(id: string) => void—Dismiss handler.
onClick() => void—Row selection handler. Providing the handler enables interaction.

Examples

Notification rows

Notification rows

Unread indicator

Unread notification

Row actions

Notification with actions

InboxPanel

InboxPanel displays notification entries supplied by the application.

InboxPanelProps props
PropTypeDefaultDescription
itemsNotificationItem[]—Notification data array.
titleReactNode"Notifications"Panel title.
onRead(id: string) => void—Mark one as read.
onDismiss(id: string) => void—Dismiss one.
onReadAll() => void—Displays a Mark all as read button while unread items exist.
onItemClick(item: NotificationItem) => void—Click handler for a row.
filterablebooleantrueAdds All / Unread filter row under the header. Ignored when views is set.
viewsInboxView[]—Replaces All and Unread views. The application filters the supplied items.
activeViewstring—Controlled selected view key.
defaultActiveViewstring—Initial selected key for an uncontrolled custom view row.
onViewChange(key: string) => void—A view was picked.
searchableboolean—Adds a search band between the header and the views.
searchValuestring—Controlled search text.
onSearchChange(value: string) => void—Delegates search filtering to the application. When omitted, the field filters items locally.
searchPlaceholderstring"Search notifications"Placeholder for the search field.
unreadCountnumber—Header badge total. Defaults to the unread rows in items, which undercounts a paginated list.
headerActionsReactNode—Right-aligned header content. Pointer presses in this area do not start dragging.
footerReactNode—Footer content below the scrolling list.
loadingboolean—Swaps the list for placeholder rows while the first page loads.
groupedboolean—Section rows under their category.
emptyMessageReactNode"You're all caught up."Message when the list is empty.
maxHeightnumber380List max height in px.
widthnumber | string320pxPanel width.

InboxPanel example

ImportTSX
import { Notification, InboxPanel, Button } from "@solarius/onset";
import type { NotificationItem } from "@solarius/onset";

const items: NotificationItem[] = [
  {
    id: "1",
    title: "Deployment completed",
    body: "v2.4.1 deployed",
    time: new Date(),
    tone: "ok",
  },
  {
    id: "2",
    title: "Storage at 85%",
    body: "Upgrade plan",
    time: new Date(),
    tone: "warn",
  },
];

<InboxPanel
  items={items}
  onRead={(id) => markRead(id)}
  onDismiss={(id) => dismiss(id)}
  onReadAll={() => markAllRead()}
  filterable
/>;

Server-backed inbox

For server-backed history, pass views, controlled searchValue, and a footer. The application handles queries and supplies items; the panel does not filter them. Set unreadCount to the server total when only part of the inbox is loaded.

Server-backedTSX
<InboxPanel
  items={page.items}
  loading={loading}
  unreadCount={page.unreadCount}
  views={[
    { key: "all", label: "All" },
    { key: "unread", label: "Unread", count: page.unreadCount },
    { key: "archived", label: "Archived" },
  ]}
  activeView={view}
  onViewChange={setView}
  searchable
  searchValue={search}
  onSearchChange={setSearch}
  headerActions={
    <Button size="sm" variant="ghost" onClick={openSettings}>
      Settings
    </Button>
  }
  footer={
    cursor ? (
      <Button size="sm" variant="ghost" onClick={loadMore}>
        Load more
      </Button>
    ) : null
  }
/>