This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13) .

Message Composer UI

The message composer is a primary interaction surface in chat, so custom layouts should preserve the SDK’s composer behavior for uploads, autocomplete, quoted messages, and submission.

Best Practices

  • Compose custom input UI from exported building blocks instead of duplicating composer state.
  • Keep TextareaComposer central so autocomplete and slash commands still work.
  • Read cooldown through useCooldownRemaining() or CooldownTimer, not from MessageComposerContext.
  • Render custom input UI by scoping WithComponents overrides={{ MessageComposerUI: ... }} around the target composer subtree.
  • Decide whether your custom layout should match the default command-selected state, where the attachment selector and extra actions collapse while CommandChip is active.
  • Test quoted-message, attachment, link-preview, and voice-recording states together.

You can compose a custom input from the exported pieces used by MessageComposerUI:

import {
  AttachmentPreviewList,
  CooldownTimer,
  LinkPreviewList,
  MessageComposerActions,
  QuotedMessagePreview,
  SendButton,
  SimpleAttachmentSelector,
  TextareaComposer,
  VoiceRecordingPreviewSlot,
  useCooldownRemaining,
  useMessageComposerContext,
} from "stream-chat-react";

const SendButtonWithCooldown = () => {
  const cooldownRemaining = useCooldownRemaining();
  const { handleSubmit } = useMessageComposerContext();

  return cooldownRemaining ? (
    <CooldownTimer />
  ) : (
    <SendButton sendMessage={handleSubmit} />
  );
};

const CustomMessageComposer = () => (
  <div className="message-input">
    <div className="left-container">
      <SimpleAttachmentSelector />
    </div>
    <div className="central-container">
      <QuotedMessagePreview />
      <VoiceRecordingPreviewSlot />
      <AttachmentPreviewList />
      <LinkPreviewList />
      <TextareaComposer />
    </div>
    <div className="right-container">
      <MessageComposerActions />
      <SendButtonWithCooldown />
    </div>
  </div>
);

If you want the default slash-command layout too, keep the str-chat__message-composer* wrappers and toggle the same str-chat__message-composer--command-active class when a command is selected. The built-in composer uses that state to collapse the attachment selector and additional action buttons while keeping CommandChip visible next to the textarea.

Render the custom layout through MessageComposer so the SDK still provides the required composer context:

import {
  Channel,
  ChannelHeader,
  MessageComposer,
  MessageList,
  Thread,
  WithComponents,
  Window,
} from "stream-chat-react";

const App = () => (
  <Channel>
    <Window>
      <ChannelHeader />
      <MessageList />
      <WithComponents overrides={{ MessageComposerUI: CustomMessageComposer }}>
        <MessageComposer />
      </WithComponents>
    </Window>
    <Thread />
  </Channel>
);