Skip to main content
FieldValue
Package@cometchat/chat-uikit-react
FrameworkReact Router
ComponentsCometChatConversations, CometChatMessageHeader, CometChatMessageList, CometChatMessageComposer
LayoutTwo-panel — conversation list (left) + message view (right)
PrerequisiteComplete React Router Integration Steps 1–5 first
SSRLazy import + mounted check — CometChat requires browser APIs
PatternWhatsApp Web, Slack, Microsoft Teams
This guide builds a two-panel chat layout — conversation list on the left, messages on the right. Users tap a conversation to open it. This assumes you’ve already completed React Router Integration (project created, UI Kit installed, CSS imported).

What You’re Building

Three sections working together:
  1. Sidebar (conversation list) — shows all active conversations (users and groups)
  2. Message view — displays chat messages for the selected conversation in real time
  3. Message composer — text input with support for media, emojis, and reactions

Step 1 — Create the Sidebar Component

src
app
CometChatSelector
CometChatSelector.tsx
CometChatSelector.css
CometChatSelector.tsx
import { useEffect, useState } from "react";
import { Conversation, Group, User, CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatConversations, CometChatUIKitLoginListener } from "@cometchat/chat-uikit-react";
import "./CometChatSelector.css";

interface SelectorProps {
  onSelectorItemClicked?: (input: User | Group | Conversation, 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 | undefined
  >();

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

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

Step 2 — Create the CometChatNoSSR Component

This component handles init, login, and renders the full chat experience. It runs client-side only.
src
app
CometChatNoSSR
CometChatNoSSR.tsx
CometChatNoSSR.css
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 (dev only)
};

const UID = "cometchat-uid-1"; // Replace with your actual UID

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

  useEffect(() => {
    if (typeof window === "undefined") return;

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

    CometChatUIKit.init(UIKitSettings)
      ?.then(() => {
        console.log("Initialization completed successfully");
        setInitialized(true);
        CometChatUIKit.getLoggedinUser().then((loggedInUser) => {
          if (!loggedInUser) {
            CometChatUIKit.login(UID)
              .then((u) => {
                console.log("Login Successful", { u });
                setUser(u);
              })
              .catch((error) => console.error("Login failed", error));
          } else {
            console.log("Already logged-in", { loggedInUser });
            setUser(loggedInUser);
          }
        });
      })
      .catch((error) => console.error("Initialization failed", error));
  }, []);

  if (!initialized || !user) {
    return <div>Initializing Chat...</div>;
  }

  return (
    <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);
              setSelectedGroup(undefined);
            } else if (item instanceof CometChat.Group) {
              setSelectedUser(undefined);
              setSelectedGroup(item);
            } 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 a conversation to start chatting</div>
      )}
    </div>
  );
};

export default CometChatNoSSR;

Step 3 — Disable SSR and Add the Route

Create CometChat.tsx inside the routes folder. This uses lazy loading and a mounted check to ensure CometChat only runs client-side.
routes/CometChat.tsx
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>
  );
}
Add the route to your routes config:
routes.ts
import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/home.tsx"),
  route("chat", "routes/CometChat.tsx"),
] satisfies RouteConfig;
CometChat depends on browser APIs (window, WebSocket, document). The lazy import + mounted check ensures the component only renders on the client.

Step 4 — Run the Project

npm run dev
Navigate to /chat (e.g. http://localhost:5173/chat). You should see the conversation list on the left. Tap any conversation to load messages on the right.

Next Steps

Theming

Customize colors, fonts, and styles to match your brand

Components Overview

Browse all prebuilt UI components

React Router Integration

Back to the main setup guide

Core Features

Chat features included out of the box