# Message composer UI

> **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/).

The message composer UI is where a user writes, edits and sends a message. The message being written lives in a `MessageComposer` object from `stream-chat`: its text, attachments, quoted message, poll and location. The UI renders that object and calls it when the user acts. This page covers which composer the UI drives, the parts of the UI and what each part reads. The props are in the [MessageComposer reference](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message-composer/messagecomposer/), and the object is on [Message composer](https://getstream.io/chat/docs/sdk/react/v15/state/writing-messages/message-composer/).

![The default message composer](https://getstream.io/docs-assets/images/3a4d8c540e93.png)

## Which composer it drives

`<MessageComposer />` and every part inside it work on the composer that `useMessageComposerController()` returns. The hook picks the first of:

1. a composer supplied with `MessageComposerControllerProvider`, for a composition you own, such as editing a message in a dialog;
2. the thread's composer, `thread.messageComposer`, inside a `Thread`;
3. the channel's composer, `channel.messageComposer`.

Editing uses the same composer. When the user picks "Edit" on a message, the action saves what the composer holds and loads the message into it. The composer is then in edit mode: `editedMessage` is set in its state, the edited-message preview shows, and sending saves the edit. Cancelling the edit puts back what the user was writing before.

When `MessageComposer` unmounts, it saves a draft of the thread's or channel's composer, if drafts are turned on, and clears it. A supplied composer is saved but never cleared; it belongs to whoever supplied it. [Drafts](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/drafts/) covers drafts.

## Previews

Above the input, the composer shows what the message will carry. Each preview renders only when the composer has something for it:

| Preview         | Shows                                                                                       | Override key                |
| --------------- | ------------------------------------------------------------------------------------------- | --------------------------- |
| Edited message  | The message being edited, with ✕ to cancel. Takes the quoted message's place while editing. | `EditedMessagePreview`      |
| Quoted message  | The message being replied to, with ✕ to remove it                                           | `QuotedMessagePreview`      |
| Voice recording | A recording waiting to be sent                                                              | `VoiceRecordingPreviewSlot` |
| Attachments     | Files, images and videos, with their upload progress                                        | `AttachmentPreviewList`     |
| Link previews   | A card for each link in the text, while it loads and once loaded                            | `LinkPreviewList`           |
| Location        | A location to share. It can't be removed while editing.                                     | None                        |

## The input

`TextareaComposer` is the text input. It reads and writes `textComposer`: the text, the cursor position, the mentioned users and the active command.

Typing a trigger opens the suggestion list, `SuggestionList`: `@` suggests people and groups to mention, `/` suggests commands, and `:` suggests emoji once you add the emoji middleware from `stream-chat-react/emojis` to the text composer. Each item is a `SuggestionListItem`. The suggestions come from the text composer's middleware; [Suggestions](https://getstream.io/chat/docs/sdk/react/v15/state/writing-messages/suggestions/) explains them.

Picking a command, such as `/giphy`, shows it as a chip before the input, `CommandChip`. The chip's ✕ clears the command.

## Actions

The attachment selector, `AttachmentSelector`, sits before the input. It opens a menu to upload a file, create a poll, share a location or pick a command. The menu is an action set, explained in [Actions](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/actions/).

After the input come two areas. The first, `AdditionalMessageComposerActions`, shows the emoji picker when you register one as the `EmojiPicker` override, except during a cooldown. The second shows one control, picked in this order:

1. **The cooldown timer**, `CooldownTimer`, while slow mode stops the user from sending. It shows the seconds left. See [Slow mode](https://getstream.io/chat/docs/sdk/react/v15/features/channels/slow-mode/).
2. **The record button**, `StartRecordingAudioButton`, when the composer is empty, nothing is being edited, no command is active, voice recording is turned on with `<MessageComposer audioRecordingEnabled />`, and the browser can record. While the user records, `AudioRecorder` replaces the whole composer. See [Voice recordings and audio playback](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/voice-recordings-and-audio-playback/).
3. **The stop button**, `StopAIGenerationButton`, while an AI is thinking or generating a reply in the channel. It calls `Channel.stopAIResponse()`. Register `StopAIGenerationButton: null` to turn it off. See [SDK integration](https://getstream.io/chat/docs/sdk/react/v15/features/ai/sdk-integration/).
4. **The send button**, `SendButton`, otherwise. It is disabled until the composer has something to send, and shows a checkmark while editing or with a command.

## In threads

In a thread, the composer shows a checkbox, `SendToChannelCheckbox`, that also posts the reply to the channel. It reads "Also send in channel", or "Also send as a direct message" in a channel with two members. It toggles `showReplyInChannel` in the composer's state, and is hidden while editing.

## Drag and drop

Files dropped on the composer are uploaded into it. The composer UI wraps itself in `WithDragAndDropUpload`, which shows "Drag your files here" while files are dragged over it, and refuses the files that `attachments.acceptedFiles` in the composer configuration doesn't accept.

To accept drops on a larger area, such as the whole channel, wrap that area in `WithDragAndDropUpload`. Files dropped anywhere in it go to the composers inside:

```tsx title="src/ChannelWithDropZone.tsx"
import {
  Channel,
  ChannelHeader,
  MessageComposer,
  MessageList,
  WithDragAndDropUpload,
} from "stream-chat-react";

export const ChannelWithDropZone = () => (
  <Channel channel={channel}>
    <WithDragAndDropUpload className="channel-drop-zone" component="section">
      <ChannelHeader />
      <MessageList />
      <MessageComposer />
    </WithDragAndDropUpload>
  </Channel>
);
```

The composer's own drop zone turns off during a cooldown and when the user can't upload files. The props are in the [WithDragAndDropUpload reference](https://getstream.io/chat/docs/sdk/react/v15/component-reference/utilities/withdraganddropupload/).

## What each part reads

Each part subscribes to the store of the composer piece it shows, and calls that piece when the user acts:

| Composer piece        | Used by                                                                                    |
| --------------------- | ------------------------------------------------------------------------------------------ |
| `state`               | The quoted and edited message previews, the send button, the also-send-to-channel checkbox |
| `textComposer`        | The input, the suggestion list, the command chip                                           |
| `attachmentManager`   | The attachment and voice recording previews, drag and drop, the attachment selector        |
| `linkPreviewsManager` | The link previews                                                                          |
| `pollComposer`        | The poll creation dialog                                                                   |
| `locationComposer`    | The location preview and the share location dialog                                         |
| `customDataManager`   | No built-in part. It holds custom fields that your own parts add to the message.           |

A part of your own reads the same way: get the composer with `useMessageComposerController()` and subscribe to a store with `useStateStore`. This one counts the characters typed, beside the emoji picker:

```tsx title="src/ComposerWithCount.tsx"
import type { TextComposerState } from "stream-chat";
import {
  AdditionalMessageComposerActions,
  MessageComposer,
  useMessageComposerController,
  useStateStore,
  WithComponents,
} from "stream-chat-react";

const textSelector = ({ text }: TextComposerState) => ({ text });

const CharacterCount = () => {
  const { textComposer } = useMessageComposerController();
  const { text } = useStateStore(textComposer.state, textSelector);

  return <span className="character-count">{text.length}</span>;
};

// Renders the default part too, so the emoji picker stays.
const ActionsWithCount = () => (
  <>
    <CharacterCount />
    <AdditionalMessageComposerActions />
  </>
);

const overrides = { AdditionalMessageComposerActions: ActionsWithCount };

export const ComposerWithCount = () => (
  <WithComponents overrides={overrides}>
    <MessageComposer />
  </WithComponents>
);
```

The same part works in a channel, in a thread and while editing, because the hook returns the composer of the place it is rendered in.

## Replacing parts

Register replacements with `WithComponents`. [Overriding components](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/overriding-components/) explains how overrides apply.

| Override key                                               | Replaces                                                              |
| ---------------------------------------------------------- | --------------------------------------------------------------------- |
| `MessageComposerUI`                                        | The whole composer UI. `MessageComposer` still provides the composer. |
| `EditedMessagePreview`, `QuotedMessagePreview`             | The edited and quoted message previews                                |
| `AttachmentPreviewList`, `VoiceRecordingPreviewSlot`       | The attachment and voice recording previews                           |
| `LinkPreviewList`                                          | The link previews                                                     |
| `TextareaComposer`                                         | The input                                                             |
| `AutocompleteSuggestionList`, `AutocompleteSuggestionItem` | The suggestion list and each suggestion                               |
| `CommandChip`                                              | The command chip                                                      |
| `AttachmentSelector`                                       | The attachment selector                                               |
| `AttachmentSelectorInitiationButtonContents`               | The contents of the button that opens the selector                    |
| `PollCreationDialog`, `ShareLocationDialog`                | The dialogs the selector opens                                        |
| `AdditionalMessageComposerActions`, `EmojiPicker`          | The area after the input, and the emoji picker in it                  |
| `SendButton`                                               | The send button. Gets `sendMessage`.                                  |
| `CooldownTimer`                                            | The cooldown timer                                                    |
| `StartRecordingAudioButton`, `AudioRecorder`               | The record button and the recorder                                    |
| `StopAIGenerationButton`                                   | The stop button. `null` turns it off.                                 |
| `SendToChannelCheckbox`                                    | The also-send-to-channel checkbox                                     |

The defaults of `EditedMessagePreview`, `SendToChannelCheckbox` and `StopAIGenerationButton` aren't exported, so a replacement for one of them can't render the default inside it.

The [Custom composer recipe](https://getstream.io/chat/docs/sdk/react/v15/recipes/composer/custom-composer/) builds a composer UI of its own.

## Used in

- [Sending, editing and deleting](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/sending-editing-and-deleting/)
- [Drafts](https://getstream.io/chat/docs/sdk/react/v15/features/messaging/drafts/)
- [Attachments and uploads](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/attachments-and-uploads/)
- [Polls](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/polls/)
- [Location sharing](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/location-sharing/)
- [Link previews](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/link-previews/)
- [Commands and Giphy](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/commands-and-giphy/)
- [Emoji](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/emoji/)
- [Custom composer](https://getstream.io/chat/docs/sdk/react/v15/recipes/composer/custom-composer/), [Attachment previews](https://getstream.io/chat/docs/sdk/react/v15/recipes/composer/attachment-previews/), [Attachment actions](https://getstream.io/chat/docs/sdk/react/v15/recipes/composer/attachment-actions/) and [Custom suggestions](https://getstream.io/chat/docs/sdk/react/v15/recipes/composer/custom-suggestions/)

---

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