Composer UI components
The default 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 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 asTextareaComposerandMessageComposerActions, readMessageComposerContextand throw outside it. - Keep
TextareaComposerin a custom layout, so mentions, commands and the Enter key keep working. - The default layout passes a few parts what they need, such as
commandtoCommandChipandsendMessagetoSendButton. 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 |
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 |
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 |
AttachmentPreviewList |
AttachmentPreviewList |
The files, images and videos in the composer | Below |
LinkPreviewList |
LinkPreviewList |
A card for each link in the text | Below |
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 |
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 |
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 |
AudioRecorder |
AudioRecorder |
The recorder, in place of the composer while 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 |
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-activeclass to the composer; - shows
CommandChipbefore the input; - hides
AttachmentSelectorandAdditionalMessageComposerActionswith 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 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 lists the fields of MessageComposerPreviewVisibilityFilterParams.
The components registered under EditedMessagePreview, QuotedMessagePreview, VoiceRecordingPreviewSlot, AttachmentPreviewList and LinkPreviewList render inside the default items. Replacing parts says when each of them mounts. Message composer UI 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:
placeholderreplaces "Send a message". A command's placeholder and the cooldown's "Slow mode, wait 5s..." still take its place.classNameis added to the default class names.onChange,onKeyDownandonScrollreplace the default handling. With your ownonChange, typing no longer reaches the composer. With your ownonKeyDown, Enter no longer submits and the arrow keys no longer move through suggestions.onSelectruns before the default handling, which keeps the composer's cursor position.onPasteruns before the paste handler fromMessageComposerContext. Callevent.preventDefault()in it to skip that handler. AnonPasteon<TextareaComposer/>replacesadditionalTextareaProps.onPasteof<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 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
LinkPreviewListrenders; - voice recordings, which
VoiceRecordingPreviewSlotrenders; - the location to share, which the
locationitem 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 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 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 explains recording.
Hooks
useMessageComposerPreviewSetFilter: the items of a preview set that are visible.useMessageComposerPreviewState: the composer state thatisVisiblegets.useAttachmentManagerState: the attachments and how many more fit.useAttachmentsForPreview: the attachments, the poll and the location to preview.useMessageComposerHasSendableData: whether the send button is enabled.useMessageComposerCommands: the channel's commands and whether each one can be used.