Skip to main content

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 / APIPurpose
CometChatMessageListDisplays group messages (publishes ui:open-chat internally via “Message Privately” option)
CometChatMessageComposerText input for the private conversation
CometChatMessageHeaderDisplays user/group info
useCometChatEventsSubscribe to ui:open-chat event
ui:open-chatUI 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.
App.tsx
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:
ScenarioBehavior
User messages themselvesDisable the private message option for the logged-in user’s own messages
User is blockedCheck getBlockedByMe() before opening the private panel and show a prompt
Private panel already openReplace the current private user with the newly selected one
Group conversation changesClose the private panel when switching to a different conversation

Complete Example

App.tsx
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