Field Value Package @cometchat/chat-uikit-reactComponent CometChatMessageComposer — rich text input with attachmentsCSS Import @import url("@cometchat/chat-uikit-react/css-variables.css");Key Props user, group, attachmentOptions, textFormattersEvents ccMessageSent, ccMessageEdited, ccReplyToMessage
Overview
This guide shows you how to build a rich message input with attachments, emoji, voice recording, mentions, and custom actions. You’ll learn to customize the composer for different use cases.
Time estimate: 15 minutes
Difficulty: Intermediate
Prerequisites
Use Cases
The message composer is essential for:
Text messaging — Send plain text and formatted messages
Media sharing — Attach images, videos, audio, and files
Voice notes — Record and send voice messages
Mentions — Tag users with @mentions
Custom inputs — Add polls, locations, or custom message types
Steps
Step 1: Add Basic Composer
Add the composer to your chat view:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function BasicComposer () {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
CometChat . getUser ( "user_uid" ). then ( setUser );
}, []);
if ( ! user ) return null ;
return < CometChatMessageComposer user = { user } /> ;
}
export default BasicComposer ;
Step 2: Create a Minimal Text-Only Composer
Hide all attachment options for a simple text input:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function MinimalComposer () {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
CometChat . getUser ( "user_uid" ). then ( setUser );
}, []);
if ( ! user ) return null ;
return (
< CometChatMessageComposer
user = { user }
hideAttachmentButton = { true }
hideVoiceRecordingButton = { true }
hideEmojiKeyboardButton = { true }
hideStickersButton = { true }
placeholderText = "Type a message..."
/>
);
}
export default MinimalComposer ;
Change how the Enter key works:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import {
CometChatMessageComposer ,
EnterKeyBehavior ,
} from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function EnterKeyComposer () {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
CometChat . getUser ( "user_uid" ). then ( setUser );
}, []);
if ( ! user ) return null ;
return (
< CometChatMessageComposer
user = { user }
// Options: SendMessage (default), NewLine, None
enterKeyBehavior = { EnterKeyBehavior . NewLine }
/>
);
}
export default EnterKeyComposer ;
Behavior Description SendMessageEnter sends the message (default) NewLineEnter adds a new line, Shift+Enter sends NoneEnter does nothing, must click send button
Step 4: Add Custom Attachment Options
Replace or extend the default attachment options:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import {
CometChatMessageComposer ,
CometChatMessageComposerAction ,
} from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function CustomAttachments () {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
CometChat . getUser ( "user_uid" ). then ( setUser );
}, []);
if ( ! user ) return null ;
const customAttachments = [
new CometChatMessageComposerAction ({
id: "location" ,
title: "Share Location" ,
iconURL: "/icons/location.svg" ,
onClick : () => {
console . log ( "Share location clicked" );
// Implement location sharing
},
}),
new CometChatMessageComposerAction ({
id: "contact" ,
title: "Share Contact" ,
iconURL: "/icons/contact.svg" ,
onClick : () => {
console . log ( "Share contact clicked" );
// Implement contact sharing
},
}),
new CometChatMessageComposerAction ({
id: "poll" ,
title: "Create Poll" ,
iconURL: "/icons/poll.svg" ,
onClick : () => {
console . log ( "Create poll clicked" );
// Implement poll creation
},
}),
];
return (
< CometChatMessageComposer
user = { user }
attachmentOptions = { customAttachments }
/>
);
}
export default CustomAttachments ;
Step 5: Handle Send Events
Intercept the send action for custom handling:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function CustomSendHandler () {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
CometChat . getUser ( "user_uid" ). then ( setUser );
}, []);
if ( ! user ) return null ;
return (
< CometChatMessageComposer
user = { user }
onSendButtonClick = { ( message ) => {
console . log ( "Message to send:" , message );
// Add custom logic before sending
// The message is still sent automatically
} }
onTextChange = { ( text ) => {
console . log ( "Text changed:" , text );
// Track typing, validate input, etc.
} }
onError = { ( error ) => {
console . error ( "Composer error:" , error );
} }
/>
);
}
export default CustomSendHandler ;
Display information above the composer:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function ComposerWithHeader () {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
CometChat . getUser ( "user_uid" ). then ( setUser );
}, []);
if ( ! user ) return null ;
return (
< CometChatMessageComposer
user = { user }
headerView = {
< div style = { {
padding: "8px 16px" ,
background: "#fff3cd" ,
borderRadius: "8px" ,
display: "flex" ,
alignItems: "center" ,
gap: "8px" ,
} } >
< span > ⚠️ </ span >
< span > User has paused notifications </ span >
</ div >
}
/>
);
}
export default ComposerWithHeader ;
Customize how @mentions work:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function MentionsComposer () {
const [ group , setGroup ] = useState < CometChat . Group >();
useEffect (() => {
CometChat . getGroup ( "group_guid" ). then ( setGroup );
}, []);
if ( ! group ) return null ;
return (
< CometChatMessageComposer
group = { group }
// Disable @all mentions
disableMentionAll = { false }
// Custom label for @all (default is "all")
mentionAllLabel = "everyone"
// Custom request builder for mention suggestions
mentionsGroupMembersRequestBuilder = {
new CometChat . GroupMembersRequestBuilder ( group . getGuid ())
. setLimit ( 10 )
. setSearchKeyword ( "" )
}
/>
);
}
export default MentionsComposer ;
Step 8: Thread Replies
Create a composer for threaded conversations:
import { useState , useEffect } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function ThreadComposer ({ parentMessage } : { parentMessage : CometChat . BaseMessage }) {
const [ user , setUser ] = useState < CometChat . User >();
useEffect (() => {
const sender = parentMessage . getSender ();
if ( sender ) {
CometChat . getUser ( sender . getUid ()). then ( setUser );
}
}, [ parentMessage ]);
if ( ! user ) return null ;
return (
< CometChatMessageComposer
user = { user }
parentMessageId = { parentMessage . getId () }
placeholderText = "Reply in thread..."
/>
);
}
export default ThreadComposer ;
Complete Example
Here’s a full chat view with a customized composer:
import { useState , useEffect } from "react" ;
import {
CometChatConversations ,
CometChatMessageHeader ,
CometChatMessageList ,
CometChatMessageComposer ,
CometChatMessageComposerAction ,
CometChatMessageEvents ,
} from "@cometchat/chat-uikit-react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import "@cometchat/chat-uikit-react/css-variables.css" ;
function ChatWithComposer () {
const [ selectedConversation , setSelectedConversation ] = useState < CometChat . Conversation >();
// Listen to message events
useEffect (() => {
const sentSub = CometChatMessageEvents . ccMessageSent . subscribe (( data ) => {
console . log ( "Message sent:" , data );
});
return () => {
sentSub ?. unsubscribe ();
};
}, []);
const getConversationWith = () => {
if ( ! selectedConversation ) return null ;
const type = selectedConversation . getConversationType ();
if ( type === "user" ) {
return { user: selectedConversation . getConversationWith () as CometChat . User };
}
return { group: selectedConversation . getConversationWith () as CometChat . Group };
};
const conversationWith = getConversationWith ();
// Custom attachment options
const attachmentOptions = [
new CometChatMessageComposerAction ({
id: "image" ,
title: "Photo" ,
iconURL: "/icons/image.svg" ,
}),
new CometChatMessageComposerAction ({
id: "file" ,
title: "Document" ,
iconURL: "/icons/file.svg" ,
}),
];
return (
< div style = { { display: "flex" , height: "100vh" , width: "100vw" } } >
< div style = { { width: 400 , borderRight: "1px solid #eee" } } >
< CometChatConversations
onItemClick = { ( conversation ) => setSelectedConversation ( conversation ) }
/>
</ div >
{ conversationWith ? (
< div style = { { flex: 1 , display: "flex" , flexDirection: "column" } } >
< CometChatMessageHeader { ... conversationWith } />
< CometChatMessageList { ... conversationWith } />
< CometChatMessageComposer
{ ... conversationWith }
placeholderText = "Type a message..."
hideCollaborativeDocumentOption = { true }
hideCollaborativeWhiteboardOption = { true }
hidePollsOption = { true }
onSendButtonClick = { ( message ) => {
console . log ( "Sending:" , message );
} }
/>
</ div >
) : (
< div style = { { flex: 1 , display: "grid" , placeItems: "center" , color: "#727272" } } >
Select a conversation
</ div >
) }
</ div >
);
}
export default ChatWithComposer ;
Visibility Props Reference
Prop Description hideAttachmentButtonHide entire attachment button hideImageAttachmentOptionHide image option hideVideoAttachmentOptionHide video option hideAudioAttachmentOptionHide audio option hideFileAttachmentOptionHide file option hidePollsOptionHide polls option hideCollaborativeDocumentOptionHide collaborative document hideCollaborativeWhiteboardOptionHide collaborative whiteboard hideVoiceRecordingButtonHide voice recording hideEmojiKeyboardButtonHide emoji keyboard hideStickersButtonHide stickers hideSendButtonHide send button
Key CSS Selectors Target Selector Root .cometchat-message-composerSend button .cometchat-message-composer__send-buttonSend button (active) .cometchat-message-composer__send-button-activeAttachment popover .cometchat-message-composer__secondary-button-view-attachment-button .cometchat-popover__contentEmoji popover .cometchat-message-composer__emoji-keyboard-button .cometchat-popover__contentHeader area .cometchat-message-composer__header
Example: Brand-Themed Composer .cometchat-message-composer__send-button .cometchat-button {
background : #6852d6 ;
border-radius : 50 % ;
}
.cometchat-message-composer__send-button .cometchat-button__icon {
background : white ;
}
Common Issues
The composer requires either a user or group prop. Without one, it won’t know where to send messages.
Issue Solution Messages not sending Ensure user or group prop is set Attachments not working Check file permissions and size limits Mentions not appearing Verify group membership for group chats Voice recording fails Check browser microphone permissions Custom attachments not showing Ensure attachmentOptions array is valid
For more help, see the Troubleshooting Guide or contact CometChat Support .
Next Steps