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>
);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
TextareaComposercentral so autocomplete and slash commands still work. - Read cooldown through
useCooldownRemaining()orCooldownTimer, not fromMessageInputContext. - 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
CommandChipis 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:
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>
);