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 chat interface where users can open a thread panel from any message, view the parent message with its reply count, browse threaded replies, and send new replies — all using v7 compound components and a state-based approach (no custom events needed).

Prerequisites

  • Completed the Quick Start guide
  • A running CometChatProvider setup with valid credentials
  • An existing chat screen using CometChatMessageList and CometChatMessageComposer

Components Used

ComponentPurpose
CometChatThreadHeaderDisplays the parent message and reply count at the top of the thread panel
CometChatMessageListRenders threaded replies when given a parentMessageId
CometChatMessageComposerSends replies into the thread with parentMessageId, layout="compact", and enableRichTextEditor

Step 1: Thread State Management

Store the threadedMessage in state. When set, the thread panel renders. When cleared, it closes. This mirrors the pattern used in the sample app’s CometChatThreadPanel component. File: ChatWithThreads.tsx
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";

function ChatWithThreads() {
  const [user, setUser] = useState<CometChat.User | null>(null);
  const [group, setGroup] = useState<CometChat.Group | null>(null);
  const [threadedMessage, setThreadedMessage] = useState<CometChat.BaseMessage | null>(null);

  // Thread opens when threadedMessage is set, closes when cleared
}

Step 2: Wire the Thread Trigger

Use the onThreadRepliesClick callback on CometChatMessageList to capture when a user clicks “Reply in Thread.” This sets the threaded message and opens the panel — no events required. File: ChatWithThreads.tsx
import { CometChatMessageList } from "@cometchat/chat-uikit-react";

<CometChatMessageList
  user={user ?? undefined}
  group={group ?? undefined}
  onThreadRepliesClick={(message) => setThreadedMessage(message)}
/>

Step 3: Build the Thread Panel

When threadedMessage is set, render a side panel composing CometChatThreadHeader + CometChatMessageList (with parentMessageId) + CometChatMessageComposer (with parentMessageId, layout="compact", and enableRichTextEditor). The onClose callback clears the state to dismiss the panel. File: ChatWithThreads.tsx
import {
  CometChatThreadHeader,
  CometChatMessageList,
  CometChatMessageComposer,
} from "@cometchat/chat-uikit-react";

{threadedMessage && (
  <div style={{ width: "400px", borderLeft: "1px solid #e0e0e0", display: "flex", flexDirection: "column" }}>
    <CometChatThreadHeader
      parentMessage={threadedMessage}
      onClose={() => setThreadedMessage(null)}
      onParentDeleted={() => setThreadedMessage(null)}
    />

    <div style={{ flex: 1, overflow: "hidden" }}>
      <CometChatMessageList
        parentMessageId={threadedMessage.getId()}
        user={user ?? undefined}
        group={group ?? undefined}
      />
    </div>

    <CometChatMessageComposer
      parentMessageId={threadedMessage.getId()}
      user={user ?? undefined}
      group={group ?? undefined}
      layout="compact"
      enableRichTextEditor
    />
  </div>
)}

Step 4: Handle Parent Deleted

Use the onParentDeleted prop on CometChatThreadHeader to automatically close the thread panel when the parent message is deleted by another user or a moderation action. File: ChatWithThreads.tsx
<CometChatThreadHeader
  parentMessage={threadedMessage}
  onClose={() => setThreadedMessage(null)}
  onParentDeleted={() => setThreadedMessage(null)}
/>

Complete Example

File: App.tsx
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
  CometChatProvider,
  CometChatConversations,
  CometChatMessageList,
  CometChatMessageComposer,
  CometChatMessageHeader,
  CometChatThreadHeader,
} from "@cometchat/chat-uikit-react";
import "@cometchat/chat-uikit-react/styles";

function ChatWithThreads() {
  const [user, setUser] = useState<CometChat.User | null>(null);
  const [group, setGroup] = useState<CometChat.Group | null>(null);
  const [threadedMessage, setThreadedMessage] = useState<CometChat.BaseMessage | null>(null);

  function handleConversationClick(conversation: CometChat.Conversation) {
    setThreadedMessage(null);
    const entity = conversation.getConversationWith();
    if (entity instanceof CometChat.User) {
      setUser(entity);
      setGroup(null);
    } else if (entity instanceof CometChat.Group) {
      setGroup(entity);
      setUser(null);
    }
  }

  return (
    <div style={{ display: "flex", height: "100vh" }}>
      {/* Conversations sidebar */}
      <div style={{ width: "300px", borderRight: "1px solid #e0e0e0" }}>
        <CometChatConversations onItemClick={handleConversationClick} />
      </div>

      {/* Main message 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}
                onThreadRepliesClick={(message) => setThreadedMessage(message)}
              />
            </div>
            <CometChatMessageComposer user={user ?? undefined} group={group ?? undefined} />
          </>
        )}
      </div>

      {/* Thread panel */}
      {threadedMessage && (
        <div style={{ width: "400px", borderLeft: "1px solid #e0e0e0", display: "flex", flexDirection: "column" }}>
          <CometChatThreadHeader
            parentMessage={threadedMessage}
            onClose={() => setThreadedMessage(null)}
            onParentDeleted={() => setThreadedMessage(null)}
          />
          <div style={{ flex: 1, overflow: "hidden" }}>
            <CometChatMessageList
              parentMessageId={threadedMessage.getId()}
              user={user ?? undefined}
              group={group ?? undefined}
            />
          </div>
          <CometChatMessageComposer
            parentMessageId={threadedMessage.getId()}
            user={user ?? undefined}
            group={group ?? undefined}
            layout="compact"
            enableRichTextEditor
          />
        </div>
      )}
    </div>
  );
}

function App() {
  return (
    <CometChatProvider
      appId="YOUR_APP_ID"
      region="YOUR_REGION"
      authKey="YOUR_AUTH_KEY"
    >
      <ChatWithThreads />
    </CometChatProvider>
  );
}

export default App;

Next Steps