Info:
This is release candidate documentation for Stream Chat React SDK v15. For the latest stable version, see the latest version (v14).

Input UI

The input UI is the component MessageComposer renders inside MessageComposerContext: the whole visible composer. The default is MessageComposerUI, and you replace it with the MessageComposerUI override key. Message composer UI explains its parts and what each one reads.

Best practices

  • Replace one part before you replace the whole layout. Each part has its own override key; see Composer UI components.
  • Build a custom layout from the exported parts. They read the composer themselves, so suggestions, uploads and commands keep working.
  • Scope WithComponents around one MessageComposer when only that composer should look different.
  • Keep the str-chat__message-composer* class names if you want the default styling.

Basic usage

Register your layout as MessageComposerUI. MessageComposer still provides the composer and the context:

import {
  Channel,
  MessageComposer,
  MessageList,
  SendButton,
  TextareaComposer,
  useMessageComposerSubmitFn,
  WithComponents,
} from "stream-chat-react";

const CompactComposerUI = () => {
  const submit = useMessageComposerSubmitFn();

  return (
    <div className="compact-composer">
      <TextareaComposer />
      <SendButton sendMessage={submit} />
    </div>
  );
};

const overrides = { MessageComposerUI: CompactComposerUI };

export const ChannelWithCompactComposer = () => (
  <Channel channel={channel}>
    <MessageList />
    <WithComponents overrides={overrides}>
      <MessageComposer />
    </WithComponents>
  </Channel>
);

The send button and the Enter key both submit through useMessageComposerSubmitFn(): MessageComposer.update() while a message is being edited, MessageComposer.send() otherwise.

UI customization

The default MessageComposerUI renders, in order:

  1. WithDragAndDropUpload around everything, so files dropped on the composer are uploaded into it.
  2. While a voice recording is in progress, AudioRecorder in place of all the rest.
  3. AttachmentSelector. Inside a message, as when a message is edited where it sits, SimpleAttachmentSelector instead: a plain upload button.
  4. The previews, only when there's something to preview:
    • EditedMessagePreview while a message is being edited, otherwise QuotedMessagePreview;
    • VoiceRecordingPreviewSlot;
    • AttachmentPreviewList;
    • LinkPreviewList;
    • the location to share. This preview has no override key.
  5. The controls:
    • CommandChip, while a command is selected;
    • TextareaComposer;
    • SendToChannelCheckbox, in a thread;
    • AdditionalMessageComposerActions, which holds the EmojiPicker override;
    • MessageComposerActions: the send button, the cooldown timer, the record button or the stop button for an AI reply.

Every part except WithDragAndDropUpload, MessageComposerActions and the location preview is read from an override key, so a replacement registered with WithComponents shows in the default layout too.

A custom layout can keep the same structure. This one leaves out the edit preview, the also-send-to-channel checkbox and the emoji picker:

import {
  AttachmentPreviewList,
  AttachmentSelector,
  AudioRecorder,
  LinkPreviewList,
  MessageComposer,
  MessageComposerActions,
  QuotedMessagePreview,
  TextareaComposer,
  useMessageComposerContext,
  VoiceRecordingPreviewSlot,
  WithComponents,
  WithDragAndDropUpload,
} from "stream-chat-react";

const CustomComposerUI = () => {
  const { recordingController } = useMessageComposerContext();

  return (
    <WithDragAndDropUpload
      className="str-chat__message-composer-container"
      component="div"
    >
      <div className="str-chat__message-composer">
        {recordingController.recordingState ? (
          <AudioRecorder />
        ) : (
          <>
            <AttachmentSelector />
            <div className="str-chat__message-composer-compose-area">
              <div className="str-chat__message-composer-previews">
                <QuotedMessagePreview />
                <VoiceRecordingPreviewSlot />
                <AttachmentPreviewList />
                <LinkPreviewList />
              </div>
              <div className="str-chat__message-composer-controls">
                <TextareaComposer />
                <MessageComposerActions />
              </div>
            </div>
          </>
        )}
      </div>
    </WithDragAndDropUpload>
  );
};

const overrides = { MessageComposerUI: CustomComposerUI };

export const ComposerWithCustomLayout = () => (
  <WithComponents overrides={overrides}>
    <MessageComposer audioRecordingEnabled />
  </WithComponents>
);

EditedMessagePreview, SendToChannelCheckbox and StopAIGenerationButton aren't exported, so a custom layout can't render their defaults. MessageComposerActions still renders the default stop button. When a command is selected, the default layout also adds the str-chat__message-composer--command-active class; see Command-state behavior.

The Custom composer recipe builds a complete layout.

Props

The input UI receives no props. It reads what it needs from:

  • useMessageComposerContext(): the MessageComposer props, the textarea ref and the recorder;
  • useMessageComposerController(): the composer and its stores;
  • the composer hooks, such as useMessageComposerSubmitFn() and useAttachmentManagerState().