Thread
Thread gives one thread to the components inside it and renders only them, in a str-chat__thread container. Thread UI explains what it does, and Replies and threads covers the feature.
Best practices
- Get the thread from
client.threads.ensure({ channel, parentMessage })orclient.threads.get(id), never fromnew Thread(). The client keeps one instance per thread and sends it its events. - Compose the panel from children.
Threadrenders no header, message list or composer of its own. - With
ChatView, renderThreadSlot. It rendersThreadfor the thread in its slot, around the same children. - A
Threadneeds noChannelaround it. Inside it,useChannel()returns the thread's channel. - For long threads, render
VirtualizedMessageListinside instead ofMessageList.
Basic usage
This panel opens the thread of a message:
import { useMemo } from "react";
import type { Channel as StreamChannel, LocalMessage } from "stream-chat";
import {
MessageComposer,
MessageList,
Thread,
ThreadHeader,
useChatContext,
} from "stream-chat-react";
type ThreadPanelProps = {
channel: StreamChannel;
parentMessage: LocalMessage;
};
export const ThreadPanel = ({ channel, parentMessage }: ThreadPanelProps) => {
const { client } = useChatContext();
// Returns the thread the client already has for this message, or creates it.
const thread = useMemo(
() => client.threads.ensure({ channel, parentMessage }),
[channel, client, parentMessage],
);
return (
<Thread thread={thread}>
<ThreadHeader />
<MessageList />
<MessageComposer />
</Thread>
);
};MessageList renders the parent message above the replies, and MessageComposer writes into thread.messageComposer. Thread loads the thread while its state is stale. It renders nothing until the thread has its parent message, and nothing when replies are off for the channel.
Without a layout, the replies button on a message opens nothing. Threads without ChatView keeps the open thread in state and renders this panel for it.
UI customization
Thread and ThreadHeader have no override key. Change the panel by changing its children, and the header through its props, below.
Two parts of the panel are override keys. The message list renders both:
| Override key | Replaces | Props |
|---|---|---|
ThreadHead |
The parent message, above the replies | MessageProps, with the parent as message |
ThreadStart |
The reply count under the parent message | none |
The default ThreadStart is exported, so a replacement can render it. The default ThreadHead isn't. Replies and threads replaces ThreadStart.
Inside a thread, the message list and the composer take the same override keys as in a channel. To give the thread a message UI of its own, register it inside Thread, so it applies only there:
import type { Thread as StreamThread } from "stream-chat";
import {
MessageComposer,
MessageList,
MessageText,
Thread,
ThreadHeader,
WithComponents,
} from "stream-chat-react";
const CompactReply = () => (
<div className="compact-reply">
<MessageText />
</div>
);
const threadOverrides = { MessageUI: CompactReply };
export const CompactThread = ({ thread }: { thread: StreamThread }) => (
<Thread thread={thread}>
<WithComponents overrides={threadOverrides}>
<ThreadHeader />
<MessageList />
<MessageComposer />
</WithComponents>
</Thread>
);To change the container's class names, set customClasses.thread on Chat. It replaces str-chat__thread-container str-chat__thread.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
thread |
Thread |
required | The thread to render, a Thread from stream-chat. Get it from client.threads.ensure() or client.threads.get(). |
children |
ReactNode |
none | The panel: usually ThreadHeader, MessageList and MessageComposer. |
ThreadHeader props
ThreadHeader shows "Thread" with a subtitle, the channel's name and the reply count, or who is typing. Thread UI describes it, and the Thread header recipe builds one of your own.
| Prop | Type | Default | Description |
|---|---|---|---|
StartContent |
React.ComponentType |
WorkspaceNavigationBackButton |
Rendered at the start. The default back button shows only while the thread is stacked over other content in its panel. |
EndContent |
React.ComponentType |
WorkspaceNavigationCloseButton |
Rendered at the end. The default close button shows only while the thread's panel can be closed. |
overrideTitle |
string |
the channel's name | Replaces the channel's name in the subtitle. |
A component passed as StartContent or EndContent replaces the button. Render the button inside it to keep it.
Related hooks
| Hook | Returns |
|---|---|
useThreadContext() |
the thread of the nearest Thread, or undefined outside one |
useChannel() |
inside a thread, the thread's channel |
useMessageComposerController() |
inside a thread, thread.messageComposer |
useCloseThread() |
a function that closes the thread in context through workspace navigation |
See ThreadContext and useThreadContext. With ChatView, ThreadSlot and its props are on ChatView components.