The @novu/react package offers an interface that enables you to build a custom notifications UI using React hooks that are powered by real-time data from the Novu services.

These hooks are designed for use in both mobile and web applications, offering a flexible approach to building a custom notifications UI tailored to your application’s requirements.

Getting Started

Follow these steps to get started with building your custom inbox UI:

1

Install the @novu/react package

npm install @novu/react 
2

Implement the NovuProvider

To implement the NovuProvider component, you need to place it in your application’s code at the tree level where you want the hooks to be accessible. Here’s how you can do it:

import { NovuProvider } from '@novu/react/hooks';

function App() {
  return (
    <NovuProvider
      subscriberId="YOUR_SUBSCRIBER_ID"
      applicationIdentifier="YOUR_APPLICATION_IDENTIFIER"
    >
      {/* Your app components where you want to use the hooks */}
      <YourCustomInbox />
    </NovuProvider>
  );
}

You can find the applicationIdentifier in the Novu Dashboard under the API keys page. The subscriberId is the unique identifier of the user in your application, learn more about subscribers here.

3

Create the custom Inbox UI

For example, you can create a custom popover UI with a bell icon that shows the unread notifications count and a list of notifications.

const YourCustomInbox = () => {
  return (
    <Popover.Root open={...} onOpenChange={...}>
      <Popover.Trigger>
        <BellButton />
      </Popover.Trigger>
      <Popover.Content>
        <NotificationsList />
      </Popover.Content>
    </Popover.Root>
  );
};

The BellButton component fetches the unread notifications count and renders the count value in the indicator.

import { useCounts } from '@novu/react/hooks';

const BellButton = () => {
  const { counts } = useCounts({ filters: [{ read: false }] });

  return (
    <button>
      <BellIcon>
      {counts && counts[0].count > 0 && <span>{counts[0].count}</span>}
    </button>
  );
};

The NotificationsList component retrieves and displays the notifications list with infinite scrolling functionality.

import { useNotifications } from '@novu/react/hooks';

const NotificationsList = () => {
  const { notifications, isLoading, fetchMore, hasMore } = useNotifications();

  return (
    <Show when={!isLoading} fallback={<NotificationListSkeleton />}>
      <Show
        when={notifications && notifications.length > 0}
        fallback={<EmptyNotificationList />}
      >
        <InfiniteScroll
          dataLength={notifications?.length ?? 0}
          fetchMore={fetchMore}
          hasMore={hasMore}
          loader={<LoadMoreSkeleton />}
        >
          {notifications?.map((notification) => {
            return (
              <NotificationItem
                key={notification.id}
                notification={notification}
              />
            );
          })}
        </InfiniteScroll>
      </Show>
    </Show>
  );
};

The NotificationItem component renders each notification item.

When any action is performed on the notification instance for example “read” button is clicked, the SDK will optimistically update notification that will result in the useNotifications hook rerender, so yo don’t need to refetch and manually update your UI.

const NotificationItem = ({ notification }) => {
  return (
    <div>
      {notification.isRead && <span className="dot-indicator">}
      <h3>{notification.subject}</h3>
      <p>{notification.body}</p>
      <button onClick={() => notification.read()}>Read</button>
      <button onClick={() => notification.archive()}>Archive</button>
    </div>
  );
};