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

Message Input UI

Message input 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 MessageInputContext.
  • Render custom input UI through MessageInput Input={...}.
  • 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 MessageInputFlat:

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

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

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

const CustomMessageInput = () => (
  <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 MessageInput so the SDK still provides the required composer context:

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

const App = () => (
  <Channel>
    <Window>
      <ChannelHeader />
      <MessageList />
      <MessageInput Input={CustomMessageInput} />
    </Window>
    <Thread />
  </Channel>
);