Message Input UI

Message input is used for composing and editing messages. It’s a primary interaction point in chat, so it’s worth getting right.

Message input is more than a text box + “send” button. It includes:

  1. Updating the typing status
  2. Uploading and previewing attachments
  3. Displaying link previews
  4. Auto-completing mentions, commands, emoji...

Best Practices

  • Compose input from pre-built components to preserve core behaviors.
  • Keep TextareaComposer central for autocomplete and commands.
  • Use MessageInputContext instead of passing handlers manually.
  • Avoid rendering custom inputs outside Channel/MessageInput.
  • Test attachments, previews, and typing updates together.

You can compose your Input UI component from pre-built components:

import {
  AttachmentPreviewList,
  LinkPreviewList,
  QuotedMessagePreview,
  SimpleAttachmentSelector,
  useComponentContext,
  useMessageInputContext,
} from "stream-chat-react";

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

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

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

Don’t render your custom input directly. Instead pass it as a prop to either Channel or MessageInput component. That way, your input is wrapped with the necessary context providers, especially the MessageInputContext.

import {
  Chat,
  Channel,
  ChannelHeader,
  ChannelList,
  MessageList,
  Thread,
  Window,
  MessageInput,
} from "stream-chat-react";
import { CustomMessageInput } from "./CustomMessageInput";

export const App = () => (
  <Chat client={chatClient}>
    <ChannelList filters={filters} sort={sort} options={options} />
    <Channel>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageInput Input={CustomMessageInput} />
      </Window>
      <Thread />
    </Channel>
  </Chat>
);