Documentation Index
Fetch the complete documentation index at: https://cometchat-22654f5b-react-uikit-v7.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Goal
By the end of this guide you will have a group chat interface where users can select a group member and open a private one-on-one conversation with them — without leaving the current screen. This is useful for side conversations, follow-ups, or sensitive messages that shouldn’t be shared with the entire group.
Prerequisites
- Completed the Quick Start guide
- A running
CometChatProvider setup with valid credentials
- An existing group chat screen using
CometChatMessageList and CometChatMessageComposer
Components Used
| Component / API | Purpose |
|---|
CometChatMessageList | Displays group messages (publishes ui:open-chat internally via “Message Privately” option) |
CometChatMessageComposer | Text input for the private conversation |
CometChatMessageHeader | Displays user/group info |
useCometChatEvents | Subscribe to ui:open-chat event |
ui:open-chat | UI event published when user clicks “Message Privately” |
Step 1: Set up the main layout with provider
Start with a layout that includes a conversations sidebar and a main chat area wrapped in CometChatProvider.
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
CometChatProvider,
CometChatConversations,
CometChatMessageList,
CometChatMessageComposer,
CometChatMessageHeader,
} from "@cometchat/chat-uikit-react";
import "@cometchat/chat-uikit-react/styles";
function App() {
return (
<CometChatProvider
appId="YOUR_APP_ID"
region="YOUR_REGION"
authKey="YOUR_AUTH_KEY"
>
<ChatWithPrivateMessaging />
</CometChatProvider>
);
}
export default App;
Step 2: Track group and private chat state
Maintain state for the active group conversation and a separate state for the private user when a user initiates a private message.
ChatWithPrivateMessaging.tsx
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
function ChatWithPrivateMessaging() {
const [user, setUser] = useState<CometChat.User | null>(null);
const [group, setGroup] = useState<CometChat.Group | null>(null);
const [privateUser, setPrivateUser] = useState<CometChat.User | null>(null);
// ... continued in next steps
}
Step 3: Handle conversation selection
Connect CometChatConversations to switch between user and group chats. When switching conversations, close any open private message panel.
function handleConversationClick(conversation: CometChat.Conversation) {
setPrivateUser(null); // close private panel on conversation switch
const entity = conversation.getConversationWith();
if (entity instanceof CometChat.User) {
setUser(entity);
setGroup(null);
} else if (entity instanceof CometChat.Group) {
setGroup(entity);
setUser(null);
}
}
Step 4: Initiate a private message from a group member
Use the message header or a custom action to let users pick a group member for private messaging. You can fetch the user from a member click event or from the message sender’s info.
async function handleMessagePrivately(uid: string) {
try {
const targetUser = await CometChat.getUser(uid);
setPrivateUser(targetUser);
} catch (error) {
console.error("Failed to fetch user for private messaging:", error);
}
}
Step 5: Listen for the ui:open-chat event
Use useCometChatEvents to subscribe to the ui:open-chat event, which is published internally when a user clicks “Message Privately” from the context menu. When the event fires, extract the user and open the private panel.
import { useCometChatEvents } from "@cometchat/chat-uikit-react";
import type { CometChatEvent } from "@cometchat/chat-uikit-react";
useCometChatEvents(
(event: CometChatEvent) => {
if (event.type === "ui:open-chat" && event.user) {
setPrivateUser(event.user);
}
},
[group?.getGuid()]
);
Step 6: Render the private message panel
When privateUser is set, show a side panel with a private one-on-one chat. This panel includes a header, message list, and composer scoped to the private user.
{privateUser && (
<div style={{ width: "400px", borderLeft: "1px solid #e0e0e0", display: "flex", flexDirection: "column" }}>
<div style={{ display: "flex", alignItems: "center", padding: "12px", borderBottom: "1px solid #e0e0e0" }}>
<span style={{ flex: 1, fontWeight: 600 }}>
Private: {privateUser.getName()}
</span>
<button onClick={() => setPrivateUser(null)}>✕</button>
</div>
<div style={{ flex: 1, overflow: "hidden" }}>
<CometChatMessageList user={privateUser} />
</div>
<CometChatMessageComposer user={privateUser} />
</div>
)}
Step 7: Handle edge cases
Consider these scenarios when implementing private messaging from a group:
| Scenario | Behavior |
|---|
| User messages themselves | Disable the private message option for the logged-in user’s own messages |
| User is blocked | Check getBlockedByMe() before opening the private panel and show a prompt |
| Private panel already open | Replace the current private user with the newly selected one |
| Group conversation changes | Close the private panel when switching to a different conversation |
Complete Example
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
CometChatProvider,
CometChatConversations,
CometChatMessageList,
CometChatMessageComposer,
CometChatMessageHeader,
useCometChatEvents,
} from "@cometchat/chat-uikit-react";
import type { CometChatEvent } from "@cometchat/chat-uikit-react";
import "@cometchat/chat-uikit-react/styles";
function ChatWithPrivateMessaging() {
const [user, setUser] = useState<CometChat.User | null>(null);
const [group, setGroup] = useState<CometChat.Group | null>(null);
const [privateUser, setPrivateUser] = useState<CometChat.User | null>(null);
function handleConversationClick(conversation: CometChat.Conversation) {
setPrivateUser(null);
const entity = conversation.getConversationWith();
if (entity instanceof CometChat.User) {
setUser(entity);
setGroup(null);
} else if (entity instanceof CometChat.Group) {
setGroup(entity);
setUser(null);
}
}
async function handleMessagePrivately(uid: string) {
try {
const targetUser = await CometChat.getUser(uid);
setPrivateUser(targetUser);
} catch (error) {
console.error("Failed to fetch user for private messaging:", error);
}
}
useCometChatEvents(
(event: CometChatEvent) => {
if (event.type === "ui:open-chat" && event.user) {
setPrivateUser(event.user);
}
},
[group?.getGuid()]
);
return (
<div style={{ display: "flex", height: "100vh" }}>
{/* Conversations sidebar */}
<div style={{ width: "300px", borderRight: "1px solid #e0e0e0" }}>
<CometChatConversations onItemClick={handleConversationClick} />
</div>
{/* Main chat panel */}
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
{(user || group) && (
<>
<CometChatMessageHeader user={user ?? undefined} group={group ?? undefined} />
<div style={{ flex: 1, overflow: "hidden" }}>
<CometChatMessageList
user={user ?? undefined}
group={group ?? undefined}
/>
</div>
<CometChatMessageComposer user={user ?? undefined} group={group ?? undefined} />
</>
)}
</div>
{/* Private message panel */}
{privateUser && (
<div style={{ width: "400px", borderLeft: "1px solid #e0e0e0", display: "flex", flexDirection: "column" }}>
<div style={{ display: "flex", alignItems: "center", padding: "12px", borderBottom: "1px solid #e0e0e0" }}>
<span style={{ flex: 1, fontWeight: 600 }}>
Private: {privateUser.getName()}
</span>
<button onClick={() => setPrivateUser(null)}>✕</button>
</div>
<div style={{ flex: 1, overflow: "hidden" }}>
<CometChatMessageList user={privateUser} />
</div>
<CometChatMessageComposer user={privateUser} />
</div>
)}
</div>
);
}
function App() {
return (
<CometChatProvider
appId="YOUR_APP_ID"
region="YOUR_REGION"
authKey="YOUR_AUTH_KEY"
>
<ChatWithPrivateMessaging />
</CometChatProvider>
);
}
export default App;
Next Steps