Building custom notification feed UI with hooks (headless)
Using our @knocklabs/react
and @knocklabs/client
libraries, you can create fully custom notification UIs that are backed by the Knock Feed API and real-time service.
In this guide, we'll take a look at creating a completely custom notifications UI in our application in a headless way using the Knock hooks.
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
1npm install @knocklabs/react
KnockProvider
Implement First, we'll need to implement the KnockProvider
component somewhere in your component tree and authenticate against the Knock API using a user id and API key.
1import { KnockProvider } from "@knocklabs/react";
2
3const App = ({ user }) => (
4 <KnockProvider apiKey={process.env.KNOCK_PUBLIC_API_KEY} userId={user.id}>
5 <NotificationFeed />
6 </KnockProvider>
7);
Setup the Knock client
Next, we'll need to access the instance of the Knock client created by the KnockProvider
using the useKnockClient
hook.
1import { useKnockClient } from "@knocklabs/react";
2
3const NotificationFeed = ({ user }) => {
4 const knockClient = useKnockClient();
5
6 return null;
7};
Setup the Knock feed instance
Next, we'll want to set up an instance of a Knock Feed, which will handle the state management and provide a way for us to interact with the messages on the feed.
1import {
2 useKnockClient,
3 useNotifications,
4 useNotificationStore,
5} from "@knocklabs/react";
6import { useEffect } from "react";
7
8const NotificationFeed = ({ user }) => {
9 const knockClient = useKnockClient();
10 const feedClient = useNotifications(
11 knockClient,
12 process.env.KNOCK_FEED_CHANNEL_ID,
13 );
14
15 const { items, metadata } = useNotificationStore(feedClient);
16
17 useEffect(() => {
18 feedClient.fetch();
19 }, [feedClient]);
20
21 return null;
22};
Creating a custom notifications UI
The last step is to render our notifications UI using the data that's exposed via the state store (items
and metadata
).
1import {
2 useKnockClient,
3 useNotifications,
4 useNotificationStore,
5} from "@knocklabs/react";
6import { useEffect } from "react";
7
8const NotificationFeed = ({ user }) => {
9 const knockClient = useKnockClient();
10 const feedClient = useNotifications(
11 knockClient,
12 process.env.KNOCK_FEED_CHANNEL_ID,
13 );
14
15 const { items, metadata } = useNotificationStore(feedClient);
16
17 useEffect(() => {
18 feedClient.fetch();
19 }, [feedClient]);
20
21 return (
22 <div className="notifications">
23 <span>You have {metadata.unread_count} unread items</span>
24
25 {items.map((item) => (
26 <div key={item.id}>
27 <div dangerouslySetInnerHTML={{ __html: item.blocks[0].rendered }} />
28 </div>
29 ))}
30 </div>
31 );
32};
Wrapping up
There's a lot more we can do with our notifications UI, 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