# Thread

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

`Thread` gives one thread to the components inside it and renders only them, in a `str-chat__thread` container. [Thread UI](https://getstream.io/chat/docs/sdk/react/v15/ui/components/thread-ui/#the-thread-component) explains what it does, and [Replies and threads](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/replies-and-threads/) covers the feature.

## Best practices

- Get the thread from `client.threads.ensure({ channel, parentMessage })` or `client.threads.get(id)`, never from `new Thread()`. The client keeps one instance per thread and sends it its events.
- Compose the panel from children. `Thread` renders no header, message list or composer of its own.
- With `ChatView`, render `ThreadSlot`. It renders `Thread` for the thread in its slot, around the same children.
- A `Thread` needs no `Channel` around it. Inside it, `useChannel()` returns the thread's channel.
- For long threads, render `VirtualizedMessageList` inside instead of `MessageList`.

## Basic usage

This panel opens the thread of a message:

```tsx
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](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/replies-and-threads/#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](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/replies-and-threads/#replacing-the-parent-message-area) 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:

```tsx
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`](https://getstream.io/chat/docs/sdk/react/v15/component-reference/chat/chat/#custom-classes). 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](https://getstream.io/chat/docs/sdk/react/v15/ui/components/thread-ui/#the-thread-header) describes it, and the [Thread header recipe](https://getstream.io/chat/docs/sdk/react/v15/recipes/headers/thread-header/) 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](https://getstream.io/chat/docs/sdk/react/v15/component-reference/thread-list/threadcontext/) and [useThreadContext](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/state-and-entity-hooks/#usethreadcontext). With `ChatView`, `ThreadSlot` and its props are on [ChatView components](https://getstream.io/chat/docs/sdk/react/v15/component-reference/layout/chatview-components/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/component-reference/thread-list/thread/](https://getstream.io/chat/docs/sdk/react/v15/component-reference/thread-list/thread/).