# Composer UI components

The default [input UI](https://getstream.io/chat/docs/sdk/react/component-reference/message-composer/input-ui/) is built from the parts on this page. Each part reads the composer from `useMessageComposerController()`, so it works in a channel, in a thread and while editing. [Message composer UI](https://getstream.io/chat/docs/sdk/react/ui/components/message-composer-ui/) explains what each part shows and which store it reads.

## Best practices

- Replace a part by registering it under its override key with `WithComponents`, so the default layout keeps the rest.
- Render the parts inside `MessageComposer`. Several of them, such as `TextareaComposer` and `MessageComposerActions`, read `MessageComposerContext` and throw outside it.
- Keep `TextareaComposer` in a custom layout, so mentions, commands and the Enter key keep working.
- The default layout passes a few parts what they need, such as `command` to `CommandChip` and `sendMessage` to `SendButton`. To set any other prop of a part, register a component that renders the part with it.

## Available building blocks

| Component                                      | Override key                       | What it renders                                                                                            | Props                                                                                                 |
| ---------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `TextareaComposer`                             | `TextareaComposer`                 | The text input and its suggestion list                                                                     | [Below](#textareacomposer-props)                                                                      |
| `CommandChip`                                  | `CommandChip`                      | The selected command, with ✕ to clear it                                                                   | `command`. Renders nothing without one                                                                |
| `MessageComposerPreviews`                      | `MessageComposerPreviews`          | The visible previews above the input, from a preview set                                                   | [Below](#messagecomposerpreviews-props)                                                               |
| `QuotedMessagePreview`                         | `QuotedMessagePreview`             | The message being replied to, with ✕ to remove it                                                          | `getQuotedMessageAuthor`, `renderText`                                                                |
| `EditedMessagePreview`                         | `EditedMessagePreview`             | The message being edited, with ✕ to cancel the edit                                                        | `message`, `onCancel`                                                                                 |
| `VoiceRecordingPreviewSlot`                    | `VoiceRecordingPreviewSlot`        | A voice recording waiting to be sent                                                                       | [Below](#voicerecordingpreviewslot-props)                                                             |
| `AttachmentPreviewList`                        | `AttachmentPreviewList`            | The files, images and videos in the composer                                                               | [Below](#attachmentpreviewlist-slots)                                                                 |
| `LinkPreviewList`                              | `LinkPreviewList`                  | A card for each link in the text                                                                           | [Below](#linkpreviewlist-props)                                                                       |
| `GeolocationPreview`                           | none                               | The location to share, with ✕ to remove it                                                                 | `location`, `remove`, `PreviewImage`. Without `remove`, no ✕                                          |
| `AttachmentSelector`                           | `AttachmentSelector`               | The button and menu to upload a file, create a poll, share a location or pick a command                    | [Attachment Selector](https://getstream.io/chat/docs/sdk/react/component-reference/message-composer/attachment-selector/) |
| `PollCreationDialogControls`                   | `PollCreationDialogControls`       | The footer of the poll creation dialog: Cancel, and Send Poll, which creates the poll and sends it at once | `close`, which closes the dialog (`PollCreationDialogControlsProps`)                                  |
| `AdditionalMessageComposerActions`             | `AdditionalMessageComposerActions` | The area after the input. It renders the `EmojiPicker` override, except during a cooldown                  | none                                                                                                  |
| `EmojiPicker`, from `stream-chat-react/emojis` | `EmojiPicker`                      | The emoji picker button and popover                                                                        | [Emoji Picker](https://getstream.io/chat/docs/sdk/react/component-reference/message-composer/emoji-picker/)               |
| `MessageComposerActions`                       | none                               | One of: the stop button for an AI reply, the cooldown timer, the record button, the send button            | none                                                                                                  |
| `SendButton`                                   | `SendButton`                       | The send button. Disabled until the composer has something to send                                         | `sendMessage`, and any `<button>` prop                                                                |
| `CooldownTimer`                                | `CooldownTimer`                    | The seconds left of a slow-mode cooldown                                                                   | none                                                                                                  |
| `StartRecordingAudioButton`                    | `StartRecordingAudioButton`        | The record button                                                                                          | [Audio Recorder](https://getstream.io/chat/docs/sdk/react/component-reference/voice-recording/audio-recorder/)            |
| `AudioRecorder`                                | `AudioRecorder`                    | The recorder, in place of the composer while recording                                                     | [Audio Recorder](https://getstream.io/chat/docs/sdk/react/component-reference/voice-recording/audio-recorder/)            |
| not exported                                   | `StopAIGenerationButton`           | The button that stops an AI reply. `null` turns it off                                                     | any `<button>` prop                                                                                   |
| not exported                                   | `SendToChannelCheckbox`            | The "Also send in channel" checkbox, in a thread and not while editing                                     | none                                                                                                  |
| `WithDragAndDropUpload`                        | none                               | A drop zone that uploads files into the composers inside it                                                | [WithDragAndDropUpload](https://getstream.io/chat/docs/sdk/react/component-reference/utilities/withdraganddropupload/)    |
| `FileDragAndDropContent`                       | `FileDragAndDropContent`           | The "Drag your files here" overlay of `<WithDragAndDropUpload/>`                                           | `isDragRejected`                                                                                      |

`MessageComposerActions` picks its control in this order: the stop button while an AI is thinking or generating a reply; the cooldown timer during a cooldown; the record button when the composer is empty, nothing is being edited, no command is active and recording is turned on; the send button otherwise. While editing or with a command, the default send button shows a checkmark.

## Command-state behavior

When the user selects a command, such as `/giphy`, the default layout:

- adds the `str-chat__message-composer--command-active` class to the composer;
- shows `CommandChip` before the input;
- hides `AttachmentSelector` and `AdditionalMessageComposerActions` with a CSS transition, and takes them out of the tab order;
- leaves the record button out of `MessageComposerActions`;
- changes the placeholder of the input to the command's arguments, or to "Search GIFs" for `/giphy`.

Escape, or Backspace in an empty input, clears the command. A custom layout gets the chip and the placeholder from the parts, and decides the rest itself. [Commands and Giphy](https://getstream.io/chat/docs/sdk/react/features/rich-content/commands-and-giphy/) explains commands.

## MessageComposerPreviews props

| Prop                        | Type                              | Default                            | Description                             |
| --------------------------- | --------------------------------- | ---------------------------------- | --------------------------------------- |
| `messageComposerPreviewSet` | `MessageComposerPreviewSetItem[]` | `defaultMessageComposerPreviewSet` | The previews, in the order they render. |

It renders the items whose `isVisible` holds, and nothing when none does. Each item has these fields:

| Field       | Type                                                               | Description                                                                                     |
| ----------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
| `type`      | `string`                                                           | Names the preview. Unique within a set.                                                         |
| `Component` | `React.ComponentType`                                              | The preview. It renders without props; read the composer with `useMessageComposerController()`. |
| `isVisible` | `(state: MessageComposerPreviewVisibilityFilterParams) => boolean` | Whether the preview shows for the current composer state.                                       |

[`useMessageComposerPreviewState`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#usemessagecomposerpreviewstate) lists the fields of `MessageComposerPreviewVisibilityFilterParams`.

The components registered under `EditedMessagePreview`, `QuotedMessagePreview`, `VoiceRecordingPreviewSlot`, `AttachmentPreviewList` and `LinkPreviewList` render inside the default items. [Replacing parts](https://getstream.io/chat/docs/sdk/react/ui/components/message-composer-ui/#replacing-parts) says when each of them mounts. [Message composer UI](https://getstream.io/chat/docs/sdk/react/ui/components/message-composer-ui/#previews) lists the default items and when each one shows.

## TextareaComposer props

`TextareaComposer` takes every `<textarea>` prop except `defaultValue`, `disabled`, `style` and `value`, and these:

| Prop                             | Type                                                           | Default                                            | Description                                                                |
| -------------------------------- | -------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------- |
| `closeSuggestionsOnClickOutside` | `boolean`                                                      | `true`                                             | Closes the suggestion list when the user clicks outside it.                |
| `containerClassName`             | `string`                                                       | none                                               | Class name added to the `div` around the textarea and the suggestion list. |
| `listClassName`                  | `string`                                                       | none                                               | Class name added to the suggestion list.                                   |
| `maxRows`                        | `number`                                                       | the `MessageComposer` prop, or `10`                | The most rows the input grows to.                                          |
| `minRows`                        | `number`                                                       | the `MessageComposer` prop                         | The fewest rows the input shows. Without it, an empty input is one row.    |
| `shouldSubmit`                   | `(event: React.KeyboardEvent<HTMLTextAreaElement>) => boolean` | the `MessageComposer` prop, or Enter without Shift | Decides which key press submits.                                           |

Some `<textarea>` props behave in a particular way:

- `placeholder` replaces "Send a message". A command's placeholder and the cooldown's "Slow mode, wait 5s..." still take its place.
- `className` is added to the default class names.
- `onChange`, `onKeyDown` and `onScroll` replace the default handling. With your own `onChange`, typing no longer reaches the composer. With your own `onKeyDown`, Enter no longer submits and the arrow keys no longer move through suggestions.
- `onSelect` runs before the default handling, which keeps the composer's cursor position.
- `onPaste` runs before the paste handler from `MessageComposerContext`. Call `event.preventDefault()` in it to skip that handler. An `onPaste` on `<TextareaComposer/>` replaces `additionalTextareaProps.onPaste` of `<MessageComposer/>`.

The input is disabled while the composer's `text.enabled` setting is `false`, and during a slow-mode cooldown.

## LinkPreviewList props

| Prop               | Type     | Default | Description                                 |
| ------------------ | -------- | ------- | ------------------------------------------- |
| `displayLinkCount` | `number` | `1`     | How many link previews show, in text order. |

The list shows the previews that are loading or loaded. To show more than one, register a `LinkPreviewList` that renders the default with `displayLinkCount`. [Link previews](https://getstream.io/chat/docs/sdk/react/features/rich-content/link-previews/) explains them.

## AttachmentPreviewList slots

`AttachmentPreviewList` renders the files, images and videos in the composer, each with its upload progress, and opens images and videos in a gallery. It leaves out:

- link previews, which `LinkPreviewList` renders;
- voice recordings, which `VoiceRecordingPreviewSlot` renders;
- the location to share, which the `location` item of the preview set renders with `<GeolocationPreview/>`.

Each slot replaces the preview of one kind of attachment:

| Prop                           | Type                                                                                      | Default                        | Previews                      |
| ------------------------------ | ----------------------------------------------------------------------------------------- | ------------------------------ | ----------------------------- |
| `AudioAttachmentPreview`       | `ComponentType<AudioAttachmentPreviewProps> \| ComponentType<FileAttachmentPreviewProps>` | the file preview               | Audio files                   |
| `FileAttachmentPreview`        | `ComponentType<FileAttachmentPreviewProps>`                                               | the file preview               | Other files                   |
| `ImageAttachmentPreview`       | `ComponentType<ImageAttachmentPreviewProps>`                                              | the media preview              | Images                        |
| `UnsupportedAttachmentPreview` | `ComponentType<UnsupportedAttachmentPreviewProps>`                                        | `UnsupportedAttachmentPreview` | Attachments of any other type |
| `VideoAttachmentPreview`       | `ComponentType<MediaAttachmentPreviewProps>`                                              | the media preview              | Videos                        |

Each preview gets the `attachment`, `removeAttachments` to remove it, and `handleRetry`, which uploads it again in place with `AttachmentManager.uploadFile()` and does nothing while `attachmentManager.isUploadEnabled` is `false`, as [Retrying a failed upload](https://getstream.io/chat/docs/sdk/react/state/writing-messages/attachments/#retrying-a-failed-upload) explains. Image and video previews also get `openPreview`, which opens the gallery at that attachment. The default file and media previews aren't exported. `AudioAttachmentPreviewProps` and `MediaAttachmentPreviewProps` aren't exported either; read them from `AttachmentPreviewListProps`, as in `AttachmentPreviewListProps["VideoAttachmentPreview"]`.

To set the slots, register an `AttachmentPreviewList` that renders the default with them. The [Attachment previews recipe](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/composer/attachment-previews/) does this.

## Upload progress and size indicators

The previews show an upload with these components:

| Component                         | Props                                         | What it renders                                                                                                                                                                                  |
| --------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `UploadProgressIndicator`         | `uploadProgress`, `uploadConfirmationPending` | The `ProgressIndicator` override, a ring showing the percent sent. The `LoadingIndicator` override when the progress is unknown, or when every byte is sent and the server hasn't confirmed yet. |
| `AttachmentUploadedSizeIndicator` | `attachment`, `uploadProgress`                | While uploading, the `UploadedSizeIndicator` override with the bytes sent and the total. Once uploaded, the `FileSizeIndicator` override with the file's size.                                   |
| `UploadedSizeIndicator`           | `uploadedBytes`, `fullBytes`                  | "sent / total", each formatted by the `FileSizeIndicator` override.                                                                                                                              |
| `FileSizeIndicator`               | `fileSize`, `maximumFractionDigits`           | A byte size, such as "2.4 MB".                                                                                                                                                                   |

By default:

- file previews show the progress ring and the size while uploading, and the size once uploaded;
- voice recording previews show the progress ring while uploading, and the size until the recording's duration is known;
- image and video previews show the progress ring over the thumbnail, and no size.

To change these without replacing the previews, register `ProgressIndicator`, `LoadingIndicator`, `UploadedSizeIndicator` or `FileSizeIndicator` with `WithComponents`. `ProgressIndicator` gets `percent`, from 0 to 100.

## VoiceRecordingPreviewSlot props

| Prop                    | Type                                        | Default                    | Description                                                           |
| ----------------------- | ------------------------------------------- | -------------------------- | --------------------------------------------------------------------- |
| `VoiceRecordingPreview` | `ComponentType<VoiceRecordingPreviewProps>` | the voice recording player | The preview of the recording, which the user can play before sending. |

The slot shows the first voice recording in the composer, above the attachment list. It gets the same props as the attachment previews: `attachment`, `handleRetry` and `removeAttachments`. [Voice recordings and audio playback](https://getstream.io/chat/docs/sdk/react/features/rich-content/voice-recordings-and-audio-playback/) explains recording.

## Hooks

- [`useMessageComposerPreviewSetFilter`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#usemessagecomposerpreviewsetfilter): the items of a preview set that are visible.
- [`useMessageComposerPreviewState`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#usemessagecomposerpreviewstate): the composer state that `isVisible` gets.
- [`useAttachmentManagerState`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#useattachmentmanagerstate): the attachments and how many more fit.
- [`useAttachmentsForPreview`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#useattachmentsforpreview): the attachments, the poll and the location to preview.
- [`useMessageComposerHasSendableData`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#usemessagecomposerhassendabledata): whether the send button is enabled.
- [`useMessageComposerCommands`](https://getstream.io/chat/docs/sdk/react/reference/hooks/composer-hooks/#usemessagecomposercommands): the channel's commands and whether each one can be used.

---

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