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 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
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-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 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:

  • 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 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 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