Info:
This is release candidate documentation for Stream Chat React Native SDK v10. For the latest stable version, see the latest version (v9).

Notifications

Notifications are the short messages the SDK shows after something happens: "Message pinned" after a pin, "Error uploading attachment" after a failed upload. This page covers what users see and when, and points to the pages that explain each part.

What users get

The user pins a message in a channel:

  1. "Message pinned" animates in at the bottom of the message list, with a check icon.
  2. Three seconds after it appears, it animates out.
  3. On Android, the notification is a live region, so TalkBack reads it when it appears.

If the pin fails, an error notification appears in the same place: the error's message, or "Error pinning message" when the error has none.

What users see follows a few rules:

  • Where. A notification appears in the part of the screen where it happened: the channel, the thread, the channel list, the thread list, or a channel details screen.
  • One at a time. Each part of the screen shows one notification: the newest one, or a notification without a duration ahead of any other. The list removes the others. There is no queue.
  • How long. A notification stays three seconds by default, counted from when it appears, and one with action buttons stays at least five. One without a duration stays until the user closes it, and shows a close button.
  • Until the user leaves. When the user leaves a screen, for example by going back from a channel, the notifications for that screen are removed.
  • In the user's language. The text is translated with the rest of the UI.

A lost connection is different. It isn't a notification. The message list and the channel list show a "Reconnecting..." bar of their own. Connection status covers it.

How it works across the layers

  • State. Every notification lives in client.notifications, the client's notification manager. It holds the list in client.notifications.store, and a default duration for each severity: error, warning, info and success. stream-chat publishes there itself when an upload, a send, an edit, a poll vote or a jump to a message goes wrong. Each notification has a type, such as api:attachment:upload:failed, that says what it's about. Publishing notifications explains the manager, the types and the full list of what stream-chat publishes.
  • UI. The SDK's components publish with useNotificationApi(): message actions, channel actions, member actions, the channel details lists, polls, voice recording, audio playback and reactions. The hook tags each notification for the part of the screen the component sits in, its notification target. A NotificationList serves each target: the MessageList or MessageFlashList of a channel or a thread, the ChannelList, the ThreadList and each channel details screen. A list shows the notifications tagged for its target, one at a time, and starts each one's countdown when it shows it. Notification renders one notification: its icon, its translated text, its action buttons and a close button.
  • Navigation. Not involved. A notification follows the component that published it: a pin inside a Thread goes to that thread's list, on whichever screen the thread is.

A notification tagged system is shown by no list. The app renders it with useSystemNotifications().

Displaying notifications explains the targets and how notifications reach them, translation, system notifications, and what each component publishes.

Turning it on or off

Notifications are always on, and nothing in client.config or the dashboard turns them off. What a user can trigger depends on their capabilities. A user who can't pin messages has no Pin action, so never sees "Message pinned".

To show none, replace the Notification component with one that renders nothing. Every list renders it, including the lists of the channel details screens, so the lists still start each countdown and remove each notification:

import type { PropsWithChildren } from "react";
import { WithComponents } from "stream-chat-react-native";
import type { ComponentOverrides } from "stream-chat-react-native";

// The lists keep running, but render nothing.
const overrides: ComponentOverrides = { Notification: () => null };

export const WithoutNotifications = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);

Replacing NotificationList with a component that renders nothing hides the notifications of the message lists, ChannelList and ThreadList, but not those of the channel details screens, which render the default list directly. No countdown starts in a replaced list, so its notifications stay in client.notifications.store until your code removes them.

Customizing

Publishing your own

Call addNotification from useNotificationApi() in a component inside Chat. The notification goes to the target the component sits in:

import { Pressable, Text } from "react-native";
import { useNotificationApi } from "stream-chat-react-native";

export const FavoriteButton = ({
  onFavorite,
}: {
  onFavorite: () => Promise<void>;
}) => {
  const { addNotification } = useNotificationApi();

  const favorite = async () => {
    try {
      await onFavorite();
      addNotification({
        message: "Added to favorites",
        options: { severity: "success", type: "app:channel:favorite:success" },
        origin: { emitter: "FavoriteButton" },
      });
    } catch (error) {
      addNotification({
        message: "Could not add to favorites",
        options: {
          originalError: error instanceof Error ? error : undefined,
          severity: "error",
          type: "app:channel:favorite:failed",
        },
        origin: { emitter: "FavoriteButton" },
      });
    }
  };

  return (
    <Pressable accessibilityRole="button" onPress={favorite}>
      <Text>Favorite</Text>
    </Pressable>
  );
};

The message is shown as you pass it, so translate it first. Routing notifications shows how to send it to another target. Outside React, publish with client.notifications.add(), as in Publishing a notification.

How long notifications stay

The durations are client settings, set per severity. Naming one keeps the others at three seconds:

client.config.set({
  client: { notifications: { durations: { error: 8000 } } },
});

Configuration explains client.config, and Severity, actions and durations covers the duration of one notification and notifications that stay.

Where and how they look

What they say

The text of a built-in notification comes from a translation key. Override the key the component published with, or the notifications.* key of a stream-chat notification, as Translating notifications explains.

What screen readers hear

The default Notification is an Android live region: assertive for errors, polite for the rest. VoiceOver has no live regions, and the SDK's announcer doesn't read notifications. To have a notification read on both platforms, announce it yourself with useAccessibilityAnnouncer(), as Accessibility shows.

System notifications

A notification about the whole app, rather than one screen, is a system notification. Publish it with addSystemNotification, and render it where you want with useSystemNotifications(), as System notifications shows.

Reference