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

Overview

Stream Chat React is a React SDK for chat on the Stream Chat API: team and social messaging, livestream chat, customer support and similar apps.

It has two layers:

  • State lives in stream-chat, the JavaScript client. Channels, threads, message lists and composers are objects that keep their data in reactive stores. You configure them through client.config.
  • UI lives in stream-chat-react. Its components read those stores and re-render when they change. You replace any of them through WithComponents. Its optional layout part, stream-chat-react/slot-layout with ChatView, decides where a channel or a thread opens.

To see the two layers work together, read How the SDK is built. It follows one message from the composer to the message list.

The SDK components cover:

  • Channel lists, message lists and the message composer
  • Threads, the thread list and quoted replies
  • Reactions, mentions and slash commands
  • Image, video and file attachments, with uploads
  • Voice recordings and audio playback
  • Polls and location sharing
  • Read state, unread counts and typing indicators
  • Search across channels, messages and users

Start here

Build with Stream CLI and Agent Skills

The Stream CLI and Agent Skills provide AI coding agents, such as Claude Code, Cursor, and Codex, with the tools and knowledge necessary to build apps with Stream.

Install the CLI and add the skills to your project:

curl -fsSL https://getstream.io/cli.sh | bash
getstream skills stream-react

Once installed, invoke it from your agent:

/stream Add Stream Chat to my React app.

The /stream skill acts as a router, reading your request and dispatching it to the specialist skill. You can also invoke the /stream-react skill directly.

Stream Agent Skills can also be installed from skills.sh.

Best practices

  • Start with the SDK's components and replace only the parts that need a different design.
  • Use built-in features (threads, reactions, uploads, indicators) before building your own.
  • Change behaviour through client.config, and appearance through WithComponents and CSS variables. Both stay in place when you update the SDK.
  • Check that your target browsers are on the supported list below.

What's new in v15

v15 is an architectural release. The UI is largely unchanged; what moved is where state lives, how a channel gets on screen, and how the SDK is configured.

State lives in the low-level client

Messages, channel lists, threads, search and the composer are owned by stream-chat objects, each holding a StateStore. Components subscribe to the slice they render with useStateStore, so there is one source for any value and no copy kept in React.

For example, this badge shows the number of unread threads and updates when it changes:

import type { ThreadManagerState } from "stream-chat";
import { useChatContext, useStateStore } from "stream-chat-react";

// Declared outside the component, so the subscription isn't recreated on every render.
const selector = (state: ThreadManagerState) => ({
  unreadThreadCount: state.unreadThreadCount,
});

export const UnreadThreadsBadge = () => {
  const { client } = useChatContext();
  const { unreadThreadCount } = useStateStore(client.threads.state, selector);

  return <span>{unreadThreadCount} unread threads</span>;
};

ChannelStateContext and ChannelActionContext are gone with it. State is read from the instance, and actions are called on it. See Reactive state and Reading state in components.

Pagination is a shared model

One BasePaginator backs channel lists, message history, thread replies, reminders and user groups, with cursors, ordering and loading state in one place. Let's take channel pagination as an example. ChannelList takes a ChannelPaginator as its data source, and client.channelManager keeps every registered channel paginator in sync from a single set of websocket subscriptions, so several lists can coexist. For channel lists, see ChannelManager and ChannelPaginator.

Layout is a plugin, and several channels can be active

Several Channel components can be mounted at once, each bound to its own channel by prop. Each one activates its channel with Channel.activate(), so the client knows which channels are in use: it keeps them loaded and reloads them after a reconnect. See Entity lifecycle. There is no single selected channel in the chat context. Which channel is on screen is a layout question, answered by the slot layout plugin, which ships as its own entry point. Core components navigate through workspace navigation, an interface that is inert when no layout plugin is installed. An app can use the plugin, or implement the interface over its own layout.

One place to configure instances

client.config is a configuration registry for the objects the SDK builds: channels, threads, composers, paginators and the client's own managers. It replaces the per-component request-handler props, and it is where a setup function goes when configuration values cannot express the customization. See Configuration.

Localization by stable keys

Translation keys are namespaced identifiers rather than English sentences, with the copy inline at each call site. English is the only bundled language, and a partial custom dictionary is safe because an unsupplied key still renders. See translations.

Upgrading from v14 is covered in the v15 migration guide.

Architecture

The two layers are two packages, and they meet in stores.

State: stream-chat. The client creates one Channel object per channel and one Thread object per thread. Each keeps its data in stores. For a channel, channel.state holds the members, read state and typing users, channel.messagePaginator holds the loaded messages, and channel.messageComposer holds what the user is writing. WebSocket events update these stores. You configure these objects through client.config. None of this depends on React.

UI: stream-chat-react. A component subscribes to the part of a store it shows, with useStateStore, and re-renders when that part changes. Chat gives every component below it the client, read with useChatContext(). Channel gives its children a channel and Thread a thread, read with useChannel() and useThreadContext(). You replace any component through WithComponents.

Layout: stream-chat-react/slot-layout. This part of the UI is optional. SDK components open channels and threads through useWorkspaceNavigation(), and ChatView decides where each one appears. Without a layout, opening does nothing, and the app renders Channel and Thread where it wants them.

For example, when a new message arrives, channel.messagePaginator adds it to its store. MessageList subscribes to that store, so it re-renders with the new message. React keeps no copy of the messages.

Supported platforms

Our React Chat SDK can run on all modern browsers and platforms released after April 2024. Here is the list of supported platforms:

  • Chrome 124+
  • Firefox 124+
  • Edge 124+
  • Safari and Mobile Safari 17.4+
Note:

Although the SDK works on other exotic and older browser versions, these are the ones we officially support and test on, so we recommend using them for the best experience.

What's next

FAQ

How do I upgrade from v14?

Follow the v15 upgrade guide.

Can I show in-app notifications for chat events?

Yes. The notifications guide covers useNotificationApi and the NotificationList component.

Does chat include moderation?

Yes. AI engines screen messages and users can flag content into a dashboard review queue. See moderation for chat.