Skip to main content
FieldValue
Package@cometchat/chat-uikit-react
FrameworkReact.js
ComponentsCometChatConversations, CometChatCallLogs, CometChatUsers, CometChatGroups, CometChatMessageHeader, CometChatMessageList, CometChatMessageComposer
LayoutTabbed sidebar (Chats, Calls, Users, Groups) + message view
PrerequisiteComplete React.js Integration Steps 1–5 first
PatternFull-featured messaging app with multiple sections
This guide builds a tabbed messaging UI — Chats, Calls, Users, and Groups tabs in the sidebar, with a message view on the right. Good for full-featured apps that need more than just conversations. This assumes you’ve already completed React.js Integration (project created, UI Kit installed, init + login working, CSS imported).
Fork the sandbox, insert your CometChat credentials (App ID, Region, Auth Key), and preview the UI in real time.

What You’re Building

Three sections working together:
  1. Tab bar — switches between Chats, Calls, Users, and Groups
  2. Sidebar — renders the list for the active tab (conversations, call logs, users, or groups)
  3. Message view — header + messages + composer for the selected item

Step 1 — Create the Tab Component

Create a CometChatTabs folder inside src/:
src
CometChatTabs
assets
chats.svg
calls.svg
users.svg
groups.svg
CometChatTabs.tsx
CometChatTabs.css
Download the tab icons from the CometChat UI Kit assets folder on GitHub.
CometChatTabs.tsx
import { useState } from "react";
import chatsIcon from "./assets/chats.svg";
import callsIcon from "./assets/calls.svg";
import usersIcon from "./assets/users.svg";
import groupsIcon from "./assets/groups.svg";
import "./CometChatTabs.css";

export const CometChatTabs = (props: {
  onTabClicked?: (tabItem: { name: string; icon?: string }) => void;
  activeTab?: string;
}) => {
  const { onTabClicked = () => {}, activeTab } = props;
  const [hoverTab, setHoverTab] = useState("");

  const tabItems = [
    { name: "CHATS", icon: chatsIcon },
    { name: "CALLS", icon: callsIcon },
    { name: "USERS", icon: usersIcon },
    { name: "GROUPS", icon: groupsIcon },
  ];

  return (
    <div className="cometchat-tab-component">
      {tabItems.map((tabItem) => (
        <div
          key={tabItem.name}
          className="cometchat-tab-component__tab"
          onClick={() => onTabClicked(tabItem)}
        >
          <div
            className={
              activeTab === tabItem.name.toLowerCase() ||
              hoverTab === tabItem.name.toLowerCase()
                ? "cometchat-tab-component__tab-icon cometchat-tab-component__tab-icon-active"
                : "cometchat-tab-component__tab-icon"
            }
            style={
              tabItem.icon
                ? {
                    WebkitMaskImage: `url("${tabItem.icon}")`,
                    maskImage: `url("${tabItem.icon}")`,
                  }
                : undefined
            }
            onMouseEnter={() => setHoverTab(tabItem.name.toLowerCase())}
            onMouseLeave={() => setHoverTab("")}
          />
          <div
            className={
              activeTab === tabItem.name.toLowerCase() ||
              hoverTab === tabItem.name.toLowerCase()
                ? "cometchat-tab-component__tab-text cometchat-tab-component__tab-text-active"
                : "cometchat-tab-component__tab-text"
            }
            onMouseEnter={() => setHoverTab(tabItem.name.toLowerCase())}
            onMouseLeave={() => setHoverTab("")}
          >
            {tabItem.name}
          </div>
        </div>
      ))}
    </div>
  );
};

Step 2 — Create the Sidebar Component

The sidebar renders the list for whichever tab is active, plus the tab bar at the bottom.
src
CometChatSelector
CometChatSelector.tsx
CometChatSelector.css
CometChatSelector.tsx
import { useEffect, useState } from "react";
import {
  Call,
  Conversation,
  Group,
  User,
  CometChat,
} from "@cometchat/chat-sdk-javascript";
import {
  CometChatCallLogs,
  CometChatConversations,
  CometChatGroups,
  CometChatUIKitLoginListener,
  CometChatUsers,
} from "@cometchat/chat-uikit-react";
import { CometChatTabs } from "../CometChatTabs/CometChatTabs";
import "./CometChatSelector.css";

interface SelectorProps {
  onSelectorItemClicked?: (
    input: User | Group | Conversation | Call,
    type: string
  ) => void;
}

export const CometChatSelector = (props: SelectorProps) => {
  const { onSelectorItemClicked = () => {} } = props;
  const [loggedInUser, setLoggedInUser] = useState<CometChat.User | null>();
  const [activeItem, setActiveItem] = useState<
    CometChat.Conversation | CometChat.User | CometChat.Group | CometChat.Call | undefined
  >();
  const [activeTab, setActiveTab] = useState<string>("chats");

  useEffect(() => {
    const user = CometChatUIKitLoginListener.getLoggedInUser();
    setLoggedInUser(user);
  }, []);

  return (
    <>
      {loggedInUser && (
        <>
          {activeTab === "chats" ? (
            <CometChatConversations
              activeConversation={
                activeItem instanceof CometChat.Conversation ? activeItem : undefined
              }
              onItemClick={(e) => {
                setActiveItem(e);
                onSelectorItemClicked(e, "updateSelectedItem");
              }}
            />
          ) : activeTab === "calls" ? (
            <CometChatCallLogs
              activeCall={
                activeItem instanceof CometChat.Call ? activeItem : undefined
              }
              onItemClick={(e: Call) => {
                setActiveItem(e);
                onSelectorItemClicked(e, "updateSelectedItemCall");
              }}
            />
          ) : activeTab === "users" ? (
            <CometChatUsers
              activeUser={
                activeItem instanceof CometChat.User ? activeItem : undefined
              }
              onItemClick={(e) => {
                setActiveItem(e);
                onSelectorItemClicked(e, "updateSelectedItemUser");
              }}
            />
          ) : activeTab === "groups" ? (
            <CometChatGroups
              activeGroup={
                activeItem instanceof CometChat.Group ? activeItem : undefined
              }
              onItemClick={(e) => {
                setActiveItem(e);
                onSelectorItemClicked(e, "updateSelectedItemGroup");
              }}
            />
          ) : null}
        </>
      )}
      <CometChatTabs
        activeTab={activeTab}
        onTabClicked={(item) => setActiveTab(item.name.toLowerCase())}
      />
    </>
  );
};
Key points:
  • The activeTab state drives which list component renders — CometChatConversations, CometChatCallLogs, CometChatUsers, or CometChatGroups.
  • Each list component passes its selection back to the parent via onSelectorItemClicked with a type string so the parent knows what was selected.
  • CometChatTabs renders at the bottom of the sidebar.

Step 3 — Update App.tsx and App.css

Wire everything together. The app handles selections from any tab — conversations, users, groups, or calls.
App.tsx
import { useState } from "react";
import {
  CometChatMessageComposer,
  CometChatMessageHeader,
  CometChatMessageList,
} from "@cometchat/chat-uikit-react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatSelector } from "./CometChatSelector/CometChatSelector";
import "./App.css";
import "@cometchat/chat-uikit-react/css-variables.css";

function App() {
  const [selectedUser, setSelectedUser] = useState<CometChat.User | undefined>(undefined);
  const [selectedGroup, setSelectedGroup] = useState<CometChat.Group | undefined>(undefined);
  const [selectedCall, setSelectedCall] = useState<CometChat.Call | undefined>(undefined);

  return (
    <div className="conversations-with-messages">
      {/* Sidebar — tabs + list */}
      <div className="conversations-wrapper">
        <CometChatSelector
          onSelectorItemClicked={(activeItem) => {
            let item = activeItem;

            // Extract user/group from Conversation object
            if (activeItem instanceof CometChat.Conversation) {
              item = activeItem.getConversationWith();
            }

            if (item instanceof CometChat.User) {
              setSelectedUser(item as CometChat.User);
              setSelectedGroup(undefined);
              setSelectedCall(undefined);
            } else if (item instanceof CometChat.Group) {
              setSelectedUser(undefined);
              setSelectedGroup(item as CometChat.Group);
              setSelectedCall(undefined);
            } else if (item instanceof CometChat.Call) {
              // Add custom logic for call details here
              setSelectedUser(undefined);
              setSelectedGroup(undefined);
              setSelectedCall(item as CometChat.Call);
            }
          }}
        />
      </div>

      {/* Message view */}
      {selectedUser || selectedGroup || selectedCall ? (
        <div className="messages-wrapper">
          <CometChatMessageHeader user={selectedUser} group={selectedGroup} />
          <CometChatMessageList user={selectedUser} group={selectedGroup} />
          <CometChatMessageComposer user={selectedUser} group={selectedGroup} />
        </div>
      ) : (
        <div className="empty-conversation">
          Select a conversation to start chatting
        </div>
      )}
    </div>
  );
}

export default App;
How it works:
  • Selections from any tab (Chats, Calls, Users, Groups) flow through the same onSelectorItemClicked callback.
  • Conversation items are unwrapped via getConversationWith() to extract the underlying User or Group.
  • Call selections are tracked separately in selectedCall — add your own call details UI as needed.
  • Only one of selectedUser / selectedGroup / selectedCall is set at a time — the others are cleared.

Step 4 — Run the Project

npm run dev
You should see the tab bar at the bottom of the sidebar. Switch between Chats, Calls, Users, and Groups — tapping any item loads the message view on the right.

Next Steps