MessageInput

MessageInput wraps the logic, state, and UI for composing messages. It provides MessageInputContext to its children, which all input UI components consume.

Best Practices

  • Keep MessageInput under Channel so context and actions are available.
  • Use custom Input only when you need layout changes, not minor styling.
  • Prefer composer middleware over overrideSubmitHandler for message logic.
  • Avoid deprecated isThreadInput; rely on messageComposer.threadId.
  • Keep textarea row limits aligned with your UX guidelines.

Basic Usage

MessageInput must be rendered under Channel. It has no required props and builds MessageInputContext using internal hooks.

If you don’t pass a custom Input, MessageInputFlat is used by default.

<Chat client={client}>
  <ChannelList />
  <Channel>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>

UI Customization

MessageInput doesn’t render UI itself; customization is handled by the Input UI component passed via the Input prop on Channel or MessageInput.

Props

additionalTextareaProps

Additional props to be consumed by the underlying TextareaComposer component.

type additionalTextareaProps = Omit<
  React.TextareaHTMLAttributes<HTMLTextAreaElement>,
  "defaultValue" | "style" | "disabled" | "value"
>;

clearEditingState

Function to clear the editing state while editing a message.

Type
() => void

focus

If true, focuses the text input on component mount.

TypeDefault
booleanfalse

hideSendButton

Allows to hide MessageInput's send button. Used by MessageSimple to hide the send button in EditMessageForm.

TypeDefault
booleanfalse

Input

Custom UI component handling how the message input is rendered.

TypeDefault
componentMessageInputFlat

isThreadInput

Signals that the MessageInput is rendered in a message thread (Thread component). This prop is deprecated. Use messageComposer.threadId to determine whether a thread reply is being composed.

Type
boolean

maxRows

Max number of rows the underlying textarea component is allowed to grow.

TypeDefault
number10

minRows

Min number of rows the underlying textarea will start with.

TypeDefault
number1

overrideSubmitHandler

Function to override the default submit handler. This isn’t intended for message composition; use custom composition middleware instead (guide here: /chat/docs/sdk/react/components/message-input-components/message-composer-middleware#message-composer-middleware-overview).

type overrideSubmitHandler = (params: {
  cid: string; // target channel CID
  localMessage: LocalMessage; // object representing the local message data used for UI update
  message: Message; // object representing the payload sent to the server for message creation / update
  sendOptions: SendMessageOptions;
}) => Promise<void> | void;
import { MessageInput } from "stream-chat-react";
import type { MessageInputProps } from "stream-chat-react";

const CustomMessageInput = (props: MessageInputProps) => {
  const submitHandler: MessageInputProps["overrideSubmitHandler"] = useCallback(
    async (params: {
      cid: string;
      localMessage: LocalMessage;
      message: Message;
      sendOptions: SendMessageOptions;
    }) => {
      // custom logic goes here

      await sendMessage({ localMessage, message, options: sendOptions });
    },
    [sendMessage],
  );

  return (
    <StreamMessageInput {...props} overrideSubmitHandler={submitHandler} />
  );
};

parent

When replying in a thread, the parent message object.

Type
object

shouldSubmit

Currently, Enter is the default submission key and Shift+Enter is the default combination for the new line. If specified, this function overrides the default behavior specified previously.

Type
(event: KeyboardEvent) => boolean

Migration from versions older than 9.0.0

Property keycodeSubmitKeys has been replaced by shouldSubmit and thus is no longer supported. If you had custom key codes specified like so:

keyCodeSubmitKeys={[[16,13], [57], [48]]} // submission keys are Shift+Enter, 9, and 0

then that would newly translate to:

const shouldSubmit = (event) =>
  (event.key === 'Enter' && event.shiftKey) || event.key === '9' || event.key === '0';

...

shouldSubmit={shouldSubmit}