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

MessageInput

MessageInput provides the message-composer state, controls, and default UI for composing messages. It renders MessageInputContext for input UI components and uses MessageInputFlat by default.

Best Practices

  • Keep MessageInput under Channel so composer state, permissions, and channel actions stay in sync.
  • Use MessageInput Input={...} when only one composer instance should differ.
  • Use WithComponents for shared composer subcomponent overrides such as AttachmentSelector, LinkPreviewList, or AudioRecorder.
  • Prefer composer middleware or overrideSubmitHandler for send-pipeline logic, not for layout customization.
  • Use messageComposer.threadId to detect thread composition instead of relying on deprecated isThreadInput.

Basic Usage

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

const App = () => (
  <Channel>
    <Window>
      <ChannelHeader />
      <MessageList />
      <MessageInput />
    </Window>
    <Thread />
  </Channel>
);

UI Customization

MessageInput does not render the composer UI itself. It renders the component provided through its Input prop, or the shared Input override from WithComponents, and that UI reads data from MessageInputContext.

Replace the whole input UI for one composer

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

const CustomInput = () => (
  <div className="custom-input-shell">
    <TextareaComposer />
  </div>
);

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

Provide a shared input UI with WithComponents

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

const CustomInput = () => <div className="custom-input-shell">...</div>;

const App = () => (
  <WithComponents overrides={{ Input: CustomInput }}>
    <Channel>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageInput />
      </Window>
      <Thread />
    </Channel>
  </WithComponents>
);

Props

PropDescriptionType
additionalTextareaPropsAdditional props forwarded to TextareaComposer.Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "defaultValue" | "style" | "disabled" | "value">
asyncMessagesMultiSendEnabledWhen enabled, recorded voice messages stay in the composer preview stack instead of being sent immediately after recording completes. Defaults to false.boolean
audioRecordingConfigCustom recording configuration for voice messages.CustomAudioRecordingConfig
audioRecordingEnabledEnables voice-message recording UI. Defaults to false.boolean
emojiSearchIndexCustom emoji search implementation used by autocomplete and emoji replacement.ComponentContextValue["emojiSearchIndex"]
focusFocuses the textarea on mount. Defaults to false.boolean
hideSendButtonHides the default send button inside the current input UI. Defaults to false.boolean
InputCustom component that renders the whole composer UI. It should read data from MessageInputContext, MessageComposer, or other exported hooks instead of expecting injected props. Defaults to MessageInputFlat.React.ComponentType<MessageInputProps>
isThreadInputDeprecated flag indicating the composer is used in a thread. Prefer messageComposer.threadId.boolean
maxRowsMaximum number of rows the default TextareaComposer can grow to. Defaults to 10.number
minRowsMinimum number of rows the default TextareaComposer starts with.number
overrideSubmitHandlerOverrides the default send flow for new messages.(params: { cid: string; localMessage: LocalMessage; message: Message; sendOptions: SendMessageOptions; }) => Promise<void> | void
parentParent message used when composing a thread reply.LocalMessage
shouldSubmitOverrides the default submit shortcut. By default, Enter submits and Shift+Enter inserts a new line.(event: React.KeyboardEvent<HTMLTextAreaElement>) => boolean

Examples

Override the submit handler

import { MessageInput, type MessageInputProps } from "stream-chat-react";

const CustomMessageInput = () => {
  const overrideSubmitHandler: MessageInputProps["overrideSubmitHandler"] =
    async ({ cid, localMessage, message, sendOptions }) => {
      // custom logic here
      await sendMessageToBackend({ cid, localMessage, message, sendOptions });
    };

  return <MessageInput overrideSubmitHandler={overrideSubmitHandler} />;
};

sendMessageToBackend in the example above is app-owned code.