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