import {
Channel,
ChannelHeader,
MessageInput,
MessageList,
Thread,
Window,
} from "stream-chat-react";
const CustomInput = () => <div className="custom-input-shell">...</div>;
const App = () => (
<Channel>
<Window>
<ChannelHeader />
<MessageList />
<MessageInput Input={CustomInput} />
</Window>
<Thread />
</Channel>
);Input UI
The Input UI component consumes MessageInputContext and renders the visible composer. The default implementation is MessageInputFlat.
Best Practices
- Start from the exported building blocks before replacing the whole composer.
- Pass a custom input through
MessageInput Input={...}for one-off layouts. - Use
WithComponentsfor shared subcomponent overrides. - Keep the preview stack and textarea together so autocomplete, uploads, and recording state remain coherent.
- If you want the default slash-command UX, keep
CommandChipnext toTextareaComposerand hide attachment or extra-action controls while a command is selected. - Reuse the default
str-chat__message-composer*classes if you want to keep the built-in styling.
Basic Usage
Use MessageInput Input={...} to replace the whole composer UI for a specific instance.
UI Customization
MessageInputFlat is a good reference for a custom composer. In v14 the default structure is:
AttachmentSelector- preview stack:
EditedMessagePrevieworQuotedMessagePreviewVoiceRecordingPreviewSlotAttachmentPreviewListLinkPreviewList
- text and action controls:
CommandChipTextareaComposerSendToChannelCheckboxAdditionalMessageComposerActionsMessageComposerActions
A simplified custom input can keep the same composition model:
import {
AttachmentPreviewList,
AttachmentSelector,
LinkPreviewList,
MessageComposerActions,
MessageInput,
QuotedMessagePreview,
SendToChannelCheckbox,
TextareaComposer,
VoiceRecordingPreviewSlot,
WithDragAndDropUpload,
} from "stream-chat-react";
const CustomInput = () => (
<WithDragAndDropUpload
className="str-chat__message-composer-container"
component="div"
>
<div className="str-chat__message-composer">
<AttachmentSelector />
<div className="str-chat__message-composer-compose-area">
<div className="str-chat__message-composer-previews">
<QuotedMessagePreview />
<VoiceRecordingPreviewSlot />
<AttachmentPreviewList />
<LinkPreviewList />
</div>
<div className="str-chat__message-composer-controls">
<TextareaComposer />
<SendToChannelCheckbox />
<MessageComposerActions />
</div>
</div>
</div>
</WithDragAndDropUpload>
);
const Composer = () => <MessageInput Input={CustomInput} />;When a slash command is selected, the default MessageInputFlat adds str-chat__message-composer--command-active, keeps the selected command visible through CommandChip, and collapses both AttachmentSelector and AdditionalMessageComposerActions. Mirror that behavior in your own layout only if you want parity with the default composer.
For a shared override across the app, register the input UI with WithComponents:
import { Channel, MessageInput, WithComponents } from "stream-chat-react";
const CustomInput = () => <div className="custom-input-shell">...</div>;
const App = () => (
<WithComponents overrides={{ Input: CustomInput }}>
<Channel>
<MessageInput />
</Channel>
</WithComponents>
);Props
| Prop | Description | Type |
|---|---|---|
| none | The Input UI component itself does not receive required props. It should read the composer state it needs from useMessageInputContext(), useMessageComposer(), and the exported message-input hooks. | - |