Thread

Thread renders replies for a parent message. It maintains its own state and renders its own MessageList and MessageInput. You can override UI via props or ComponentContext.

Thread consumes the contexts from Channel and has no required props.

Best Practices

  • Always wrap main content in Window to keep layout stable when threads open.
  • Use thread-specific Message/MessageInput only when UX truly diverges.
  • Keep thread UI consistent with the main channel for familiarity.
  • Use virtualized for long-running or high-traffic threads.
  • Avoid over-customizing ThreadHeader/ThreadStart unless needed.

Basic Usage

Thread must be rendered under Channel. For smooth mount/unmount, wrap the main channel UI in Window, which handles layout changes when the thread opens.

<Chat client={client}>
  <ChannelList />
  <Channel>
    <Window>
      <MessageList />
      <MessageInput />
    </Window>
    <Thread />
  </Channel>
</Chat>

UI Customization

Thread uses most of the same pieces as Channel, so customization works similarly. You can override the thread’s Message and MessageInput via props, and override ThreadHeader/ThreadStart via ComponentContext.

Example 1 - Render different UI for the thread and the main channel.

A common pattern is: check props first, then fall back to context.

const MainInput = (props) => {
  // render main `MessageInput` UI component here
};

const MainMessage = (props) => {
  // render main `Message` UI component here
};

const ThreadInput = (props) => {
  // render thread `MessageInput` UI component here
};

const ThreadMessage = (props) => {
  // render thread `Message` UI component here
};

<Chat client={client}>
  <ChannelList />
  <Channel Input={MainInput} Message={MainMessage}>
    <Window>
      <MessageList />
      <MessageInput />
    </Window>
    <Thread Input={ThreadInput} Message={ThreadMessage} />
  </Channel>
</Chat>;

Example 2 - Provide custom UI for ThreadHeader and ThreadStart. ThreadHeader renders above the parent message, and ThreadStart separates the parent message from the reply list.

const CustomThreadHeader = (props) => {
  // render thread header UI component here
};

const CustomThreadStart = (props) => {
  // render thread start UI component here
};

<Chat client={client}>
  <ChannelList />
  <Channel ThreadHeader={CustomThreadHeader} ThreadStart={CustomThreadStart}>
    <Window>
      <MessageList />
      <MessageInput />
    </Window>
    <Thread />
  </Channel>
</Chat>;

Example 3 - Customize the parent message + ThreadStart separator by providing a ThreadHead component on Channel. It’s stored in ComponentContext['ThreadHead'].

const CustomThreadHead = (props) => {
  // render thread header UI component here
};

<Chat client={client}>
  <ChannelList />
  <Channel ThreadHead={CustomThreadHead} ThreadStart={CustomThreadStart}>
    <Window>
      <MessageList />
      <MessageInput />
    </Window>
    <Thread />
  </Channel>
</Chat>;

Props

additionalMessageInputProps

Additional props to be passed to the underlying MessageInput component.

Type
object

additionalMessageListProps

Additional props to be passed to the underlying MessageList component.

Type
object

additionalParentMessageProps

Additional props to be passed to the underlying Message component, which represents the thread's parent message.

Type
object

additionalVirtualizedMessageListProps

Additional props for VirtualizedMessageList component.

Type
object

autoFocus

If true, focuses the MessageInput component on opening a thread.

TypeDefault
booleantrue

enableDateSeparator

Controls injection of DateSeparator UI component into underlying MessageList or VirtualizedMessageList.

TypeDefault
booleanfalse

Input

Custom UI component to replace the MessageInput of a Thread. The component uses MessageInputFlat by default.

TypeDefault
componentMessageInputFlat

Message

Custom thread message UI component used to override the default Message value stored in ComponentContext.

TypeDefault
componentComponentContext['Message']

messageActions

Array of allowed message actions (ex: 'edit', 'delete', 'reply'). To disable all actions, provide an empty array.

TypeDefault
array['edit', 'delete', 'flag', 'markUnread', 'mute', 'pin', 'quote', 'react', 'remindMe', 'reply', 'saveForLater']

It is also possible to display actions that are by default supported by the SDK, but not active by default:

import {
  Thread,
  MESSAGE_ACTIONS,
  OPTIONAL_MESSAGE_ACTIONS,
} from "stream-chat-react";

const messageActions = [
  ...Object.keys(MESSAGE_ACTIONS),
  OPTIONAL_MESSAGE_ACTIONS.deleteForMe, // has to be explicitly added to the messageActions array
];

<Thread messageActions={messageActions} />;

virtualized

If true, render the VirtualizedMessageList instead of the standard MessageList component.

Type
boolean