Chat

The Chat component wraps your app and provides ChatContext, including the connected StreamChat client, the active channel, query state, and shared SDK configuration.

Best Practices

  • Render Chat once at the app root so a single client instance is shared.
  • Create and connect the client outside render loops to avoid reconnect churn.
  • Keep customClasses minimal and include the layout classes your app still depends on.
  • Use theme and CSS variables before reaching for heavy wrapper overrides.
  • Keep collapsible sidebar state in app code if your layout needs it. The SDK does not manage collapsible sidebar open/close state for you.

Basic Usage

Chat does not render UI by itself. Once you have a connected StreamChat client, pass it to Chat and render the SDK components under it.

import { Channel, Chat, MessageComposer, MessageList } from "stream-chat-react";

const App = () => (
  <Chat client={client}>
    <Channel channel={channel}>
      <MessageList />
      <MessageComposer />
    </Channel>
  </Chat>
);

Any child of Chat can access the shared state through useChatContext():

import { useChatContext } from "stream-chat-react";

const CustomChild = () => {
  const { channel, client, setActiveChannel } = useChatContext();
  return null;
};

Props

PropDescriptionType
clientThe connected StreamChat client instance.StreamChat
customClassesCustom CSS class names that replace the SDK's default container classes.CustomClasses
defaultLanguageFallback language for UI translations. Defaults to "en".SupportedTranslations
i18nInstanceCustom Streami18n instance for SDK translations.Streami18n
isMessageAIGeneratedCallback used by SDK components that need to distinguish AI-generated messages.(message: LocalMessage) => boolean
searchControllerOptional SearchController instance for the SDK search surfaces. If omitted, Chat creates one with channel, user, and message search sources.SearchController
themeTheme class names added to chat surfaces such as Channel and ChannelList. Defaults to "messaging light".string
useImageFlagEmojisOnWindowsEnables the emoji replacement font for country flags on Windows. Import stream-chat-react/css/v2/emoji-replacement.css when enabling it. Defaults to false.boolean

Examples

Custom customClasses

import type { CustomClasses } from "stream-chat-react";

const customClasses: CustomClasses = {
  channel: "custom-channel-class",
  chat: "custom-chat-class",
};

const App = () => (
  <Chat client={client} customClasses={customClasses}>
    {/* Chat children */}
  </Chat>
);

Accepted keys and the default classes they replace:

  • chat -> str-chat
  • chatContainer -> str-chat__container
  • channel -> str-chat__channel
  • channelList -> str-chat__channel-list
  • message -> str-chat__li str-chat__li--${groupStyles}
  • messageList -> str-chat__message-list
  • thread -> str-chat__thread-container str-chat__thread
  • virtualMessage -> str-chat__virtual-list-message-wrapper str-chat__li
  • virtualizedMessageList -> str-chat__virtual-list

Be careful when overriding messageList, thread, or virtualizedMessageList container classes. Those wrappers carry layout rules the SDK relies on for scrolling and virtualization.

Custom i18nInstance

import { Streami18n } from "stream-chat";

const i18nInstance = new Streami18n({ language: "es" });

<Chat client={client} i18nInstance={i18nInstance}>
  {/* Chat children */}
</Chat>;

Own Sidebar State In App Code

If your app needs a collapsible sidebar, keep that state in your own React state or context and wire it into SDK header slots. Chat no longer owns mobile-nav or sidebar open/close state.

For a fuller implementation, see the Collapsible Sidebar cookbook.

import { useState } from "react";
import {
  Channel,
  ChannelHeader,
  Chat,
  MessageComposer,
  MessageList,
  Window,
  WithComponents,
} from "stream-chat-react";

const AppShell = () => {
  const [sidebarOpen, setSidebarOpen] = useState(false);

  const SidebarToggle = () => (
    <button onClick={() => setSidebarOpen((open) => !open)} type="button">
      {sidebarOpen ? "Close sidebar" : "Open sidebar"}
    </button>
  );

  return (
    <div className={sidebarOpen ? "sidebar-open" : "sidebar-closed"}>
      <Chat client={client}>
        <WithComponents overrides={{ HeaderStartContent: SidebarToggle }}>
          <Channel channel={channel}>
            <Window>
              <ChannelHeader />
              <MessageList />
              <MessageComposer />
            </Window>
          </Channel>
        </WithComponents>
      </Chat>
    </div>
  );
};