Skip to content
kerfjsGitHub

Bell

The notifications button in the app bar, with a count of what is unread.

SourcePackage @kerf-js/veneer

Preview

tsx
import { derived, state } from '@kerf-js/core'import { Bell, Inbox, Toaster } from '@kerf-js/veneer'import type { Note } from '@kerf-js/veneer'export function WithInbox() {  const inbox = useInbox()  const unread = derived(    () => inbox.items.value.filter((n) => !n.read).length,  )  return (    <>      <Bell        count={unread}        inbox={(open) => (          <Inbox            variant="popover"            {...inbox}            open={open.value}          />        )}      />      <Toaster />    </>  )}const NOTES: Note[] = [  {    id: 'n1',    actor: 'Sam Okafor',    kind: 'mention',    verb: 'mentioned you in',    object: 'mobile-bff',    time: '9 min',    day: 'Today',    source: 'Deploys',    quote:      'Can you look at the retry ' +      'settings before we redeploy?',  },  {    id: 'n2',    actor: 'Jun Tanaka',    kind: 'approve',    verb: 'asked you to approve',    object: 'Release 2026.11',    time: '32 min',    day: 'Today',    actions: [      { id: 'approve', label: 'Approve' },      { id: 'view', label: 'View', emphasis: 'outline' },    ],  },  {    id: 'n3',    actor: 'kerf',    kind: 'system',    verb: 'failed the health check on',    object: 'd-4819',    detail: 'in ap-south',    time: '1 h',    day: 'Today',  },  {    id: 'n4',    actor: 'Mara Lindqvist',    kind: 'invite',    verb: 'invited you to',    object: 'Incident review',    detail: '· 13:00',    time: '2 h',    day: 'Today',    source: 'Calendar',    read: true,  },  {    id: 'n5',    actor: 'Priya Raman',    kind: 'comment',    verb: 'commented on',    object: 'storefront',    time: 'Yesterday',    day: 'Yesterday',    quote: 'The edge cache cut image load times in half.',    read: true,  },  {    id: 'n6',    actor: 'Lena Fischer',    kind: 'assign',    verb: 'assigned you',    object: 'Ranking v2 handover',    time: 'Yesterday',    day: 'Yesterday',    read: true,  },]const min = 60_000function useInbox() {  const items = state(NOTES)  const change = (id: string, patch: Partial<Note>) =>    (items.value = items.value.map((n) =>      n.id === id ? { ...n, ...patch } : n,    ))  return {    items,    onRead: (id: string) => change(id, { read: true }),    onReadAll: () =>      (items.value = items.value.map((n) =>        n.read ? n : { ...n, read: true },      )),    onDismiss: (id: string) =>      (items.value = items.value.filter(        (n) => n.id !== id,      )),    onRestore: (note: Note) =>      (items.value = [note, ...items.value]),    onAction: (note: Note, action: string) =>      change(note.id, {        read: true,        actions: undefined,        detail:          action === 'approve'            ? '· approved'            : note.detail,      }),  }}

Installation

npm install @kerf-js/veneer

Usage

tsx
import { Bell } from '@kerf-js/veneer'

New arrivals

The count bumps once for each batch. Opening clears it here.

tsx
import { state } from '@kerf-js/core'import { Bell, Button, Row } from '@kerf-js/veneer'export function Arrivals() {  const count = state(3)  return (    <Row gap="related">      <Bell        count={count}        onOpen={() => (count.value = 0)}      />      <Button        emphasis="outline"        tone="neutral"        size="sm"        onClick={() => count.value++}      >        A deploy failed      </Button>    </Row>  )}

Accessibility

  • Its name says the count. The badge itself is hidden from assistive technology.

API Reference

PropTypeDefaultDescription
countnumber | { value: number; } | (() => number | undefined)—A number, a state or a getter.
inbox((open: State<boolean>) => unknown)—The panel. Gets open, a state.
route(() => void)—On a phone, called instead of opening.
sideSide'bottom'Which edge it sits on.
alignAlign'end'How it lines up with what opened it.
EventTypeDefaultDescription
onOpen(() => void)—It was pressed.

Parts

Every element carries a stable name, so you can style it from your own CSS: [data-scope="bell"] [data-part="content"]

content

RelatedInboxConnection pill