MessageInput
Overview
MessageInput is a fully functional message input component, providing core chat input features such as text editing, emoji selection, file attachment, and send button. It supports various custom options, including input behavior configuration, toolbar customization, component replacement, and slot expansion, meeting the personalized requirements of different chat scenarios.
Props
Field | Type | Default Value | Description |
boolean | true | Whether to auto-focus into the input box | |
boolean | false | Whether to disable the input component | |
boolean | false | Whether to hide the send button | |
string | '' | Input box placeholder text | |
string | undefined | Root container custom CSS class name | |
React.CSSProperties | undefined | Root container custom inline style | |
'collapsed' | 'expanded' | 'collapsed' | Attachment selector display mode | |
MessageInputActions | ['EmojiPicker', 'AttachmentPicker'] | Toolbar action button configuration | |
MessageInputSlots | undefined | Slot Configuration Object | |
JSX.Element | undefined | Custom Text Editor Component | |
JSX.Element | undefined | Custom Emoji Selector Component | |
JSX.Element | undefined | Custom Attachment Selector Component | |
JSX.Element | undefined | Custom File Selector Component | |
JSX.Element | undefined | Custom Image Selector Component | |
JSX.Element | undefined | Custom Video Selector Component |
Prop Explanation
autoFocus
type:
boolean
autoFocus is used to set whether to auto-focus into the input box when mounting, default value is
true
.disabled
type:
boolean
disabled is used to set whether to disable the entire input component, including text input and all operation buttons, default value is
false
.hideSendButton
type:
boolean
hideSendButton is used to set whether to hide the send button, suitable for scenarios where custom send trigger mode is needed, default value is
false
.placeholder
type:
string
placeholder is used to set the placeholder text for the input box, default value is an empty string.
className
type:
string
className is used to set the custom CSS class name for the root container, default value is
undefined
.style
type:
React.CSSProperties
style is used to set the custom inline style for the root container, default value is
undefined
.attachmentPickerMode
type:
'collapsed' | 'expanded'
attachmentPickerMode is used to set the display mode of the attachment selector, default value is
'collapsed'
.collapsed
: Collapse mode, unfold options after clickingexpanded
: Expanded mode, display all options directlyNote:
By default, AttachmentPicker refers to the attachment selector, including file selection, image selection, and video selection.
1. When the attachmentPickerMode is "collapsed", click the attachment selector to pop up a menu displaying file selection, image selection, and video selection.
2. When attachmentPickerMode is "expanded", the attachment selector expands by default, displaying file selection, image selection, and video selection in tile display.
actions
type:
MessageInputActions
Actions for configuration toolbar display action buttons, default value
['EmojiPicker', 'AttachmentPicker']
.type BuiltInAction =| 'EmojiPicker'| 'ImagePicker'| 'FilePicker'| 'VideoPicker'| 'AttachmentPicker';type CustomAction = {key: string;label?: string | undefined;component?: React.ComponentType<any> | undefined;className?: string | undefined;style?: React.CSSProperties | undefined;iconSize?: number | undefined;};type MessageInputActions = Array<BuiltInAction | CustomAction>;
Example1: Customizing Toolbar Button Sequence
import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';function ChatWithCustomActions() {// Custom button sequence: file, image, video, emojiconst customActions = ['FilePicker', 'ImagePicker', 'VideoPicker', 'EmojiPicker'];return (<Chat><MessageInput actions={customActions} /></Chat>);}
The rendering is shown in the figure below:

Example 2: Adding Custom Action Buttons - Customer Service System Quick Reply
import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';// Quick reply componentfunction QuickReplyPicker() {const { setContent } = useMessageInputState();const quickReplies = ['Hello, happy to serve you!','Please wait, I will check for you...','Thank you for your consultation, any other issues?',The issue has been resolved. Have a pleasant life!,];const handleQuickReply = (text: string) => {setContent(text);};return (<div style={{ position: 'relative' }}><button title="quick reply">⚡</button><div style={{position: 'absolute',bottom: '100%',left: 0,background: 'white',border: '1px solid #ccc',borderRadius: '4px',padding: '8px',minWidth: '200px'}}>{quickReplies.map((reply, index) => (<divkey={index}onClick={() => handleQuickReply(reply)}style={{padding: '4px 8px',cursor: 'pointer',borderRadius: '2px'}}>{reply}</div>))}</div></div>);}function CustomerServiceChat() {const actions = [{key: 'quickReply',label: 'quick reply',component: QuickReplyPicker},'EmojiPicker','FilePicker'];return (<Chat><MessageInput actions={actions} /></Chat>);}
The rendering is shown in the figure below:

slots
type:
MessageInputSlots
Slots are used to insert custom content at specific locations in the input component, default value is
undefined
.interface MessageInputSlots {headerToolbar?: () => React.ReactNode;footerToolbar?: () => React.ReactNode;leftInline?: () => React.ReactNode;rightInline?: () => React.ReactNode;inputPrefix?: () => React.ReactNode;inputSuffix?: () => React.ReactNode;}

Example 1: Adding Message Statistics Display
import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';function ChatWithMessageStats() {const { inputRawValue } = useMessageInputState();// Header toolbar: Display character statisticsconst HeaderToolbar = () => !inputRawValue? null: (<div style={{padding: '4px 12px',fontSize: '12px',color: '#666',borderBottom: '1px solid #eee',}}>Character count:{' '}{inputRawValue?.reduce((acc, item) => acc + (item.type === 'text' ? item.content.length : 1), 0) || 0}/500</div>);// toolbar: display sending notificationconst FooterToolbar = () => (<div style={{padding: '4px 12px',fontSize: '12px',color: '#999',textAlign: 'right'}}>Press Ctrl+Enter to enter a new line</div>);return (<Chat><MessageInputslots={{headerToolbar: HeaderToolbar,footerToolbar: FooterToolbar}}/></Chat>);}
The rendering is shown in the figure below:

Example 2: Input Box Prefix/Suffix Feature
import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';function ChatWithInputPrefixSuffix() {// Input box prefix: @reminder featureconst InputPrefix = () => (<buttonstyle={{border: 'none',background: 'transparent',color: '#1890ff',cursor: 'pointer'}}onClick={() => {// Trigger @user selectionconsole.log('toggle on @user selection')}}>@</button>);// Input box suffix: voice inputconst InputSuffix = () => (<buttonstyle={{border: 'none',background: 'transparent',cursor: 'pointer'}}onClick={() => {// Start voice inputconsole.log('start voice input')}}>🎤</button>);return (<Chat><MessageInputslots={{inputPrefix: InputPrefix,inputSuffix: InputSuffix}}/></Chat>);}
The rendering is shown in the figure below:

Example 3: Fully Customizing the Toolbar on Both Sides
import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';function ChatWithCustomToolbars() {// Left-side toolbar: only retain emoji and imagesconst LeftInline = () => (<div style={{ display: 'flex', gap: '8px' }}><button>😊</button><button>📷</button></div>);// toolbar on the right: custom sending areaconst RightInline = () => (<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}><span style={{ fontSize: '12px', color: '#666' }}>Enter</span><buttonstyle={{padding: '6px 12px',background: '#1890ff',color: 'white',border: 'none',borderRadius: '4px',cursor: 'pointer'}}>Send</button></div>);return (<Chat><MessageInputslots={{leftInline: LeftInline,rightInline: RightInline}}/></Chat>);}
The rendering is shown in the figure below:

TextEditor
type:
JSX.Element
TextEditor is used to replace the default text editor component. Default value:
undefined
.Example: Integrating a Rich Text Editor
import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';// Custom rich text editorfunction RichTextEditor() {const { sendMessage } = useMessageInputState();const [inputValue, setInputValue] = useState('');const handleContentChange = (content: string) => {setInputValue(content);};const handleKeyDown = (e: React.KeyboardEvent) => {// Enter to send messageif (e.key === 'Enter') {// Trigger sending logice.preventDefault();sendMessage(inputValue);// Clear input in editable divconst editableDiv = document.querySelector('.editable-div');if (editableDiv) {editableDiv.textContent = '';}}};return (<div style={{flex: 1,border: '1px solid #d9d9d9',borderRadius: '6px',padding: '8px 12px',minHeight: '32px',maxHeight: '120px',overflow: 'auto',}}><divcontentEditableclassName="editable-div"style={{outline: 'none',minHeight: '20px',lineHeight: '20px',}}onInput={(e) => {handleContentChange(e.currentTarget.textContent || '');}}onKeyDown={handleKeyDown}/></div>);}function ChatWithRichTextEditor() {return (<Chat><MessageInput TextEditor={<RichTextEditor />} /></Chat>);}
The rendering is shown in the figure below:

EmojiPicker
type:
JSX.Element
EmojiPicker replaces the default emoji selector component, default value
undefined
.Example: Custom Emoji Panel
import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';// Custom Emoji Selectorfunction CustomEmojiPicker() {const { insertContent } = useMessageInputState();const emojiCategories = {common: ['😀', '😂', '🥰', '😍', '🤔', '😭', '😡', '👍'],hands: ['👋', '🤝', '👏', '🙏', '✌️', '🤞', '🤟', '👌'],animals: ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼'],};const [activeCategory, setActiveCategory] = useState('common');const [showPicker, setShowPicker] = useState(false);const insertEmoji = (emoji: string) => {insertContent(emoji);setShowPicker(false);};return (<div style={{ position: 'relative' }}><buttononClick={() => setShowPicker(!showPicker)}style={{ border: 'none', background: 'transparent', cursor: 'pointer' }}>😊</button>{showPicker && (<div style={{position: 'absolute',bottom: '100%',left: 0,background: 'white',border: '1px solid #ccc',borderRadius: '8px',padding: '12px',width: '280px',boxShadow: '0 4px 12px rgba(0,0,0,0.1)',}}>{/* Category tag */}<div style={{ display: 'flex', marginBottom: '8px' }}>{Object.keys(emojiCategories).map(category => (<buttonkey={category}onClick={() => setActiveCategory(category)}style={{padding: '4px 8px',border: 'none',background: activeCategory === category ? '#1890ff' : 'transparent',color: activeCategory === category ? 'white' : '#666',borderRadius: '4px',cursor: 'pointer',fontSize: '12px',}}>{category}</button>))}</div>{/* Emoji grid */}<div style={{display: 'grid',gridTemplateColumns: 'repeat(8, 1fr)',gap: '4px',}}>{emojiCategories[activeCategory].map(emoji => (<buttonkey={emoji}onClick={() => insertEmoji(emoji)}style={{border: 'none',background: 'transparent',fontSize: '20px',cursor: 'pointer',padding: '4px',borderRadius: '4px',}}>{emoji}</button>))}</div></div>)}</div>);}function ChatWithCustomEmoji() {return (<Chat><MessageInput EmojiPicker={<CustomEmojiPicker />} /></Chat>);}
The rendering is shown in the figure below:

AttachmentPicker
type:
JSX.Element
AttachmentPicker is used to replace the default attachment selector component, default value is
undefined
.Example: Attachment Selector for Storage Integration
import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';// Attachment Selector with Cloud Storage Integrationfunction CloudAttachmentPicker() {const [showPicker, setShowPicker] = useState(false);const attachmentTypes = [{ key: 'local', label: 'local file', icon: '📁' },{ key: 'cloud', label: 'cloud file', icon: '☁️' },{ key: 'recent', label: 'recent file', icon: '🕒' },{ key: 'screenshot', label: 'screenshot', icon: '📷' }];const handleAttachmentSelect = async (type: string) => {switch (type) {case 'local':// Open local file selectionconst input = document.createElement('input');input.type = 'file';input.multiple = true;input.onchange = (e) => {const files = (e.target as HTMLInputElement).files;console.log('selected local files:', files);};input.click();break;case 'cloud':// Toggle on cloud file selectionconsole.log('Toggle on cloud file selection');break;case 'recent':// Display recent filesconsole.log('Display recent files');break;case 'screenshot':// Start screenshotconsole.log('start screenshot')break;}setShowPicker(false);};return (<div style={{ position: 'relative' }}><buttononClick={() => setShowPicker(!showPicker)}style={{ border: 'none', background: 'transparent', cursor: 'pointer' }}>📎</button>{showPicker && (<div style={{position: 'absolute',bottom: '100%',left: 0,background: 'white',border: '1px solid #ccc',borderRadius: '8px',padding: '8px',minWidth: '160px',boxShadow: '0 4px 12px rgba(0,0,0,0.1)'}}>{attachmentTypes.map(type => (<divkey={type.key}onClick={() => handleAttachmentSelect(type.key)}style={{display: 'flex',alignItems: 'center',gap: '8px',padding: '8px 12px',cursor: 'pointer',borderRadius: '4px',fontSize: '14px'}}><span>{type.icon}</span><span>{type.label}</span></div>))}</div>)}</div>);}function ChatWithCloudAttachment() {return (<Chat><MessageInput AttachmentPicker={<CloudAttachmentPicker />} /></Chat>);}
The rendering is shown in the figure below:

Summary
The MessageInput component provides complete message input functionality and various custom options. By reasonably configuring Props and using the slot system, you can create an input interface that meets specific business requirements. It is recommended to choose an appropriate customized scheme based on real-world usage scenarios and maintain good user experience and performance.