Skip to main content
  • Package: @cometchat/chat-uikit-react
  • Framework: React Router
  • Key components: CometChatConversations + CometChatCallLogs + CometChatUsers + CometChatGroups
  • Required setup: CometChatUIKit.init(UIKitSettings) then CometChatUIKit.login("UID")
  • Parent guide: React Router Integration
Tab-based messaging UI with sections for Chats, Calls, Users, and Groups.

User Interface Preview

Three sections:
  1. Sidebar (Conversation List) — recent conversations with users and groups
  2. Message View — messages for the selected chat
  3. Message Composer — text input with media, emoji, and reaction support

Step-by-Step Guide

1

Create a Tab Component

Create a CometChatTabs folder inside src:
public/
├── assets
   ├── chats.svg 
   ├── calls.svg 
   ├── users.svg 
   ├── groups.svg
src/app/
│── CometChatTabs/
   ├── CometChatTabs.tsx
   ├── CometChatTabs.css 

Download the Icons

These icons are available in the CometChat UI Kit assets folder. You can find them at:
🔗 GitHub Assets Folder

Implementation

CometChatTabs.tsx
import { useState } from "react";
import "./CometChatTabs.css";

const chatsIcon = "/assets/chats.svg";
const callsIcon = "/assets/calls.svg";
const usersIcon = "/assets/users.svg";
const groupsIcon = "/assets/groups.svg";

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) => {
        const isActive =
          activeTab === tabItem.name.toLowerCase() ||
          hoverTab === tabItem.name.toLowerCase();

        return (
          <div
            key={tabItem.name}
            className="cometchat-tab-component__tab"
            onClick={() => onTabClicked(tabItem)}
          >
            <div
              className={
                isActive
                  ? "cometchat-tab-component__tab-icon cometchat-tab-component__tab-icon-active"
                  : "cometchat-tab-component__tab-icon"
              }
              style={{
                WebkitMaskImage: `url(${tabItem.icon})`,
                maskImage: `url(${tabItem.icon})`,
              }}
              onMouseEnter={() => setHoverTab(tabItem.name.toLowerCase())}
              onMouseLeave={() => setHoverTab("")}
            />
            <div
              className={
                isActive
                  ? "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>
  );
};
2

Create Sidebar

Create a CometChatSelector folder inside src/app:
src/app/
│── 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,
  CometChatUIKit,
  CometChatUIKitLoginListener,
  CometChatUsers
} from "@cometchat/chat-uikit-react";

import { CometChatTabs } from "../CometChatTabs/CometChatTabs";

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<
    Conversation | User | Group | Call | undefined
  >();
  const [activeTab, setActiveTab] = useState<string>("chats");

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

  const logOut = () => {
    CometChatUIKit.logout()
      .then(() => setLoggedInUser(null))
      .catch((error) => console.log("Logout error:", error));
  };

  return (
    <>
      {loggedInUser && (
        <>
          {activeTab === "chats" && (
            <CometChatConversations
              activeConversation={activeItem instanceof CometChat.Conversation ? activeItem : undefined}
              onItemClick={(item) => {
                setActiveItem(item);
                onSelectorItemClicked(item, "updateSelectedItem");
              }}
            />
          )}

          {activeTab === "calls" && (
            <CometChatCallLogs
              activeCall={activeItem as Call}
              onItemClick={(item: Call) => {
                setActiveItem(item);
                onSelectorItemClicked(item, "updateSelectedItemCall");
              }}
            />
          )}

          {activeTab === "users" && (
            <CometChatUsers
              activeUser={activeItem as User}
              onItemClick={(item) => {
                setActiveItem(item);
                onSelectorItemClicked(item, "updateSelectedItemUser");
              }}
            />
          )}

          {activeTab === "groups" && (
            <CometChatGroups
              activeGroup={activeItem as Group}
              onItemClick={(item) => {
                setActiveItem(item);
                onSelectorItemClicked(item, "updateSelectedItemGroup");
              }}
            />
          )}
        </>
      )}

      <CometChatTabs
        activeTab={activeTab}
        onTabClicked={(item) => setActiveTab(item.name.toLowerCase())}
      />
    </>
  );
};
3

Render Experience

Update CometChatNoSSR.tsx and CometChatNoSSR.css to import the new components:
CometChatNoSSR.tsx
import React, { useEffect, useState } from "react";
import { 
    CometChatMessageComposer, 
    CometChatMessageHeader, 
    CometChatMessageList, 
    CometChatUIKit, 
    UIKitSettingsBuilder 
} from "@cometchat/chat-uikit-react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatSelector } from "../CometChatSelector/CometChatSelector";
import "./CometChatNoSSR.css";

const COMETCHAT_CONSTANTS = {
  APP_ID: "",       // Replace with your App ID
  REGION: "",       // Replace with your Region
  AUTH_KEY: "",     // Replace with your Auth Key
};

const UID = "cometchat-uid-4"; // Replace with dynamic UID

const CometChatNoSSR: React.FC = () => {
  const [user, setUser] = useState<CometChat.User | undefined>(undefined);
  const [selectedUser, setSelectedUser] = useState<CometChat.User | undefined>(undefined);
  const [selectedGroup, setSelectedGroup] = useState<CometChat.Group | undefined>(undefined);

  useEffect(() => {
    const UIKitSettings = new UIKitSettingsBuilder()
      .setAppId(COMETCHAT_CONSTANTS.APP_ID)
      .setRegion(COMETCHAT_CONSTANTS.REGION)
      .setAuthKey(COMETCHAT_CONSTANTS.AUTH_KEY)
      .subscribePresenceForAllUsers()
      .build();

    CometChatUIKit.init(UIKitSettings)
      ?.then(() => {
        CometChatUIKit.getLoggedinUser().then((loggedInUser) => {
          if (!loggedInUser) {
            CometChatUIKit.login(UID)
              .then((user) => setUser(user))
              .catch((error) => console.error("Login failed", error));
          } else {
            setUser(loggedInUser);
          }
        });
      })
      .catch((error) => console.error("Initialization failed", error));
  }, []);

  return user ? (
    <div className="conversations-with-messages">
      <div className="conversations-wrapper">
        <CometChatSelector 
          onSelectorItemClicked={(activeItem) => {
            let item = activeItem;
            if (activeItem instanceof CometChat.Conversation) {
              item = activeItem.getConversationWith();
            } 
            if (item instanceof CometChat.User) {
              setSelectedUser(item as CometChat.User);
              setSelectedGroup(undefined);
            } else if (item instanceof CometChat.Group) {
              setSelectedUser(undefined);
              setSelectedGroup(item as CometChat.Group);
            } else {
              setSelectedUser(undefined);
              setSelectedGroup(undefined);
            }
          }} 
        />
      </div>
      
      {selectedUser || selectedGroup ? (
        <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 Conversation to start</div>
      )}
    </div>
  ) : undefined;
};

export default CometChatNoSSR;
4

Disable SSR and Render the CometChat Component

Create a file CometChat.tsx inside the routes folder:
import React, { lazy, Suspense, useEffect, useState } from "react";
import "@cometchat/chat-uikit-react/css-variables.css";

const CometChatNoSSR = lazy(() => import("../CometChatNoSSR/CometChatNoSSR"));

export default function CometChatRoute() {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  return mounted ? (
    <Suspense fallback={<div>Loading...</div>}>
      <CometChatNoSSR />
    </Suspense>
  ) : (
    <div>Loading...</div>
  );
}
Create a route for CometChat in the routes file:
import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/home.tsx"),
  route("chat", "routes/CometChat.tsx"),
] satisfies RouteConfig;
CometChat UI Kit relies on browser APIs (window, document, WebSockets). Since React Router renders on the server by default, disabling SSR for this component prevents runtime errors.
5

Update App CSS

Add the following styles to app.css:
app.css
:root {
  --background: #ffffff;
  --foreground: #171717;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}

.root {
  height: 100%;
}

html,
body {
  height: 100%;
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

body {
  color: var(--foreground);
  background: var(--background);
  font-family: Arial, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}
6

Run the Application

  1. Start the development server:
    npm run dev
    
  2. Navigate to /chat (e.g., http://localhost:3000/chat) and verify the chat interface loads.
For prop details and customization options, see the component reference pages: CometChatConversations, CometChatMessageList, CometChatMessageComposer, CometChatMessageHeader.

Next Steps