# MessageComposer

`MessageComposer` provides the message-composer state, controls, and default UI for composing messages. It renders [`MessageComposerContext`](/chat/docs/sdk/react/components/message-composer/message-composer-context/) for input UI components and uses [`MessageComposerUI`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageComposer/MessageComposerUI.tsx) by default.

## Best Practices

- Keep `MessageComposer` under `Channel` so composer state, permissions, and channel actions stay in sync.
- Scope `WithComponents` around the specific `MessageComposer` or `Thread` subtree when one composer instance should differ.
- Use `WithComponents` for shared composer subcomponent overrides such as `AttachmentSelector`, `LinkPreviewList`, or `AudioRecorder`.
- Prefer composer middleware or `overrideSubmitHandler` for send-pipeline logic, not for layout customization.
- Use `messageComposer.threadId` to detect thread composition instead of relying on deprecated `isThreadInput`.

## Basic Usage

```tsx
import {
  Channel,
  ChannelHeader,
  MessageComposer,
  MessageList,
  Thread,
  Window,
} from "stream-chat-react";

const App = () => (
  <Channel>
    <Window>
      <ChannelHeader />
      <MessageList />
      <MessageComposer />
    </Window>
    <Thread />
  </Channel>
);
```

## UI Customization

`MessageComposer` renders the `MessageComposerUI` component from `ComponentContext`. That UI reads data from `MessageComposerContext`.

### Replace the whole composer UI for one scoped subtree

```tsx
import {
  Channel,
  ChannelHeader,
  MessageComposer,
  MessageList,
  Thread,
  WithComponents,
  Window,
} from "stream-chat-react";

const CustomInput = () => <div className="custom-input-shell">...</div>;

const App = () => (
  <Channel>
    <Window>
      <ChannelHeader />
      <MessageList />
      <WithComponents overrides={{ MessageComposerUI: CustomInput }}>
        <MessageComposer />
      </WithComponents>
    </Window>
    <Thread />
  </Channel>
);
```

### Provide a shared input UI with `WithComponents`

```tsx
import {
  Channel,
  ChannelHeader,
  MessageComposer,
  MessageList,
  Thread,
  Window,
  WithComponents,
} from "stream-chat-react";

const CustomInput = () => <div className="custom-input-shell">...</div>;

const App = () => (
  <WithComponents overrides={{ MessageComposerUI: CustomInput }}>
    <Channel>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageComposer />
      </Window>
      <Thread />
    </Channel>
  </WithComponents>
);
```

## Props

| Prop                            | Description                                                                                                                                                | Type                                                                                                                                 |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `additionalTextareaProps`       | Additional props forwarded to `TextareaComposer`.                                                                                                          | `Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "defaultValue" \| "style" \| "disabled" \| "value">`                        |
| `asyncMessagesMultiSendEnabled` | When enabled, recorded voice messages stay in the composer preview stack instead of being sent immediately after recording completes. Defaults to `false`. | `boolean`                                                                                                                            |
| `audioRecordingConfig`          | Custom recording configuration for voice messages.                                                                                                         | `CustomAudioRecordingConfig`                                                                                                         |
| `audioRecordingEnabled`         | Enables voice-message recording UI. Defaults to `false`.                                                                                                   | `boolean`                                                                                                                            |
| `emojiSearchIndex`              | Custom emoji search implementation used by autocomplete and emoji replacement.                                                                             | `ComponentContextValue["emojiSearchIndex"]`                                                                                          |
| `focus`                         | Focuses the textarea on mount. Defaults to `false`.                                                                                                        | `boolean`                                                                                                                            |
| `hideSendButton`                | Hides the default send button inside the current input UI. Defaults to `false`.                                                                            | `boolean`                                                                                                                            |
| `maxRows`                       | Maximum number of rows the default `TextareaComposer` can grow to. Defaults to `10`.                                                                       | `number`                                                                                                                             |
| `minRows`                       | Minimum number of rows the default `TextareaComposer` starts with.                                                                                         | `number`                                                                                                                             |
| `overrideSubmitHandler`         | Overrides the default send flow for new messages.                                                                                                          | `(params: { cid: string; localMessage: LocalMessage; message: Message; sendOptions: SendMessageOptions; }) => Promise<void> \| void` |
| `parent`                        | Parent message used when composing a thread reply.                                                                                                         | `LocalMessage`                                                                                                                       |
| `shouldSubmit`                  | Overrides the default submit shortcut. By default, `Enter` submits and `Shift+Enter` inserts a new line.                                                   | `(event: React.KeyboardEvent<HTMLTextAreaElement>) => boolean`                                                                       |

## Examples

### Override the submit handler

```tsx
import { MessageComposer, type MessageComposerProps } from "stream-chat-react";

const CustomMessageComposer = () => {
  const overrideSubmitHandler: MessageComposerProps["overrideSubmitHandler"] =
    async ({ cid, localMessage, message, sendOptions }) => {
      // custom logic here
      await sendMessageToBackend({ cid, localMessage, message, sendOptions });
    };

  return <MessageComposer overrideSubmitHandler={overrideSubmitHandler} />;
};
```

`sendMessageToBackend` in the example above is app-owned code.


---

This page was last updated at 2026-05-22T16:32:13.520Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/components/message-composer/message-composer/](https://getstream.io/chat/docs/sdk/react/components/message-composer/message-composer/).