KnockDocs

Building custom notifications UI with React

Using our @knocklabs/react-notification-feed and @knocklabs/client libraries, you can create fully custom notification UIs that are backed by the Knock Feed API and Websockets to receive and process real-time notifications in your web application.

In this guide, we'll take a look at creating a completely custom notifications page in our application.

Getting started

To use this example, you'll need an account on Knock, as well as an in-app feed channel with a workflow that produces in-app feed messages. You'll also need:

  • A public API key for the Knock environment (set as KNOCK_PUBLIC_API_KEY)
  • The channel ID for the in-app feed (set as KNOCK_FEED_CHANNEL_ID)

Installing dependencies

Installing dependencies
1npm install @knocklabs/react-notification-feed

Adding the KnockFeedProvider

We'll need to wrap our notifications page in a KnockFeedProvider to setup a connection to Knock and connect to the authenticated user's feed. You can read more about the available props for the feed provider in the reference.

1import { KnockFeedProvider } from "@knocklabs/react-notification-feed";
2
3const NotificationsPage = () => {
4  const { user } = useCurrentUser();
5
6  return (
7    <KnockFeedProvider
8      apiKey={process.env.KNOCK_PUBLIC_API_KEY}
9      feedId={process.env.KNOCK_FEED_CHANNEL_ID}
10      userId={user.id}
11    >
12      <NotificationsList />
13    </KnockFeedProvider>
14  );
15};

Creating a custom notifications page

In our notifications page, we'll use the store exposed by the KnockFeedProvider in order to render the list of notifications that ewe have available.

1const NotificationsList = () => {
2  const { useFeedStore } = useKnockFeed();
3  const items = useFeedStore((state) => state.items);
4
5  return (
6    <div className="notifications">
7      {items.map((item) => (
8        <NotificationCell key={item.id} item={item} />
9      ))}
10    </div>
11  );
12};

Creating a notification cell

We'll want to render a notification cell for every notification in our feed. Lets wrap that behavior up in a component for easy reuse:

1type Props = {
2  item: FeedItem,
3};
4
5const NotificationCell: React.FC<Props> = ({ item }) => {
6  // Group the content blocks by the name for easy lookup
7  const blocksByName = useMemo(() => {
8    return item.blocks.reduce((acc, block) => {
9      return { ...acc, [block.name]: block };
10    }, {});
11  }, [item]);
12
13  const maybeActor = item.actors[0];
14
15  return (
16    <div className="notification-cell">
17      {maybeActor && (
18        <span class="notification-cell__actor">{maybeActor.name}</span>
19      )}
20
21      {blocksByName.body && (
22        <div
23          className="notification-cell__content"
24          dangerouslySetInnerHTML={{ __html: blocksByName.body.rendered }}
25        />
26      )}
27    </div>
28  );
29};

Wrapping up

There's a lot more we can do with our notifications page, but we'll leave that as an exercise to the reader. Here are some examples:

  • Adding mark as read, and archiving behavior to the notification cell
  • Displaying a count of the total number of notifications

Check out the feed guide in the @knocklabs/client reference to learn about the available methods.