# Custom Announcements

The SDK announces built-in events (incoming messages, notifications, Giphy actions, poll changes, search counts) to screen readers automatically. This recipe shows how to announce your own events, how to make announcements work inside custom modals, and how to reshape notification announcements.

For the model behind these APIs see the [Accessibility guide](/chat/docs/sdk/react/guides/accessibility/#announcing-to-assistive-technology).

## Announcing a custom event

Use `useAriaLiveAnnouncer` for ad-hoc, already-localized messages. It returns a bare `announce` function and must be called inside [`Chat`](/chat/docs/sdk/react/components/core-components/chat/).

```tsx
import { useAriaLiveAnnouncer, useTranslationContext } from "stream-chat-react";

const ExportButton = () => {
  const announce = useAriaLiveAnnouncer();
  const { t } = useTranslationContext();

  const onExport = async () => {
    await exportConversation();
    announce(t("Conversation exported"));
  };

  return <button onClick={onExport}>{t("Export")}</button>;
};
```

`announce(message, options)` takes `priority` (`'polite'` by default, `'assertive'` to interrupt), `delayMs` (defer so the message lands after a competing focus/typing read-out), and `dedupeMs` (announce an identical message at most once per window). It returns a `cancel` function; for a delayed announcement, call it from effect cleanup so a closing surface does not speak after it unmounts.

```tsx
import { useEffect } from "react";
import { useAriaLiveAnnouncer } from "stream-chat-react";

const UploadStatus = ({ isUploading }: { isUploading: boolean }) => {
  const announce = useAriaLiveAnnouncer();

  useEffect(() => {
    if (!isUploading) return;
    const cancel = announce("Uploading attachment", { delayMs: 300 });
    return cancel; // do not announce if the component unmounts before the delay elapses
  }, [announce, isUploading]);

  return null;
};
```

## Reusing the built-in interaction registry

If your custom component triggers one of the SDK's known interactions, prefer `useInteractionAnnouncements`. Each entry is already localized (via the `aria/*` keys) with a sensible priority and delivery policy, so you announce by intent rather than composing strings.

```tsx
import { useInteractionAnnouncements } from "stream-chat-react";

const CustomChannelPreview = ({ channel, setActiveChannel }) => {
  const { announceInteraction } = useInteractionAnnouncements();

  const onSelect = () => {
    setActiveChannel(channel);
    announceInteraction("channel.opened", {
      name: channel.data?.name ?? "channel",
    });
  };

  return <button onClick={onSelect}>{channel.data?.name}</button>;
};
```

For a rapidly-updating value (such as a live result count), pass a per-call `debounceMs` so only the settled value is spoken, and call `cancelInteraction` when the source is torn down:

```tsx
announceInteraction("search.resultCount", { count, debounceMs: 800 });
// later, when leaving search:
cancelInteraction("search.resultCount");
```

## Announcing inside a custom modal

Assistive technologies suppress live regions outside the active `aria-modal` subtree, so a message announced from inside your own modal would be silently dropped. Render an `AriaLiveOutlet` with a higher `layer` inside the modal; the SDK's announcer automatically routes announcements to it while it is mounted.

```tsx
import { AriaLiveOutlet, useAriaLiveAnnouncer } from "stream-chat-react";

const ConfirmDialog = ({ onConfirm }: { onConfirm: () => void }) => {
  const announce = useAriaLiveAnnouncer();

  return (
    <div role="dialog" aria-modal="true" aria-label="Confirm">
      <button
        onClick={() => {
          onConfirm();
          announce("Saved"); // heard because the outlet below is inside the modal
        }}
      >
        Save
      </button>
      {/* Layer above the root outlet (0). */}
      <AriaLiveOutlet layer={1} />
    </div>
  );
};
```

## Customizing notification announcements

Notifications are distinct from chat messages: they are entries your code adds to the notification system through the `addNotification` / `addSystemNotification` functions returned by [`useNotificationApi`](/chat/docs/sdk/react/guides/notifications/). `NotificationAnnouncer` reacts to those registered notifications and announces each new one (it does not watch `message.new`).

`NotificationAnnouncer` is rendered by `Chat` and read from the [`ComponentContext`](/chat/docs/sdk/react/components/contexts/component-context/). Because `Chat` consumes it at its own level, provide your override with a `ComponentProvider` that wraps `Chat`. Use it to filter which notifications are announced and to reshape the spoken text.

```tsx
import {
  Chat,
  ComponentProvider,
  NotificationAnnouncer,
} from "stream-chat-react";

const CustomNotificationAnnouncer = () => (
  <NotificationAnnouncer
    // Announce only warnings and errors; skip informational notifications.
    notificationFilter={(notification) => notification.severity !== "info"}
    // Reshape the message. `defaultMessage` includes the severity prefix; `translatedMessage`
    // is the localized body.
    buildNotificationAnnouncement={({
      defaultMessage,
      notification,
      translatedMessage,
    }) =>
      notification.severity === "error"
        ? `Error: ${translatedMessage}`
        : defaultMessage
    }
  />
);

export const App = ({ client, children }) => (
  <ComponentProvider
    value={{ NotificationAnnouncer: CustomNotificationAnnouncer }}
  >
    <Chat client={client}>{children}</Chat>
  </ComponentProvider>
);
```

<Admonition type="note">

Error-severity notifications are announced with `assertive` priority (they interrupt); all others are `polite`. Return an empty string from `buildNotificationAnnouncement` to suppress a notification without changing your filter.

</Admonition>


---

This page was last updated at 2026-07-09T16:01:12.772Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/guides/customization/accessibility/custom-announcements/](https://getstream.io/chat/docs/sdk/react/guides/customization/accessibility/custom-announcements/).