Skip to main content
FieldValue
Package@cometchat/chat-uikit-react
FrameworkAstro (with @astrojs/react islands)
ComponentsCometChatConversations, CometChatMessageHeader, CometChatMessageList, CometChatMessageComposer
LayoutTwo-panel — conversation list (left) + message view (right)
PrerequisiteComplete Astro Integration Steps 1–5 first
SSRclient:only="react" directive — 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 Astro Integration (project created, React added, UI Kit installed).

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 React Island

Create a ChatApp component inside src/components/. This is a React island that handles init, login, and renders the full chat experience.
src
components
ChatApp.tsx
ChatApp.css
ChatApp.tsx
import { useEffect, useState } from "react";
import {
  CometChatConversations,
  CometChatMessageComposer,
  CometChatMessageHeader,
  CometChatMessageList,
  CometChatUIKit,
  UIKitSettingsBuilder,
} from "@cometchat/chat-uikit-react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import "@cometchat/chat-uikit-react/css-variables.css";
import "./ChatApp.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

export default function ChatApp() {
  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(() => {
        console.log("Initialization completed successfully");
        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 (!user) return <div>Initializing Chat...</div>;

  return (
    <div className="conversations-with-messages">
      <div className="conversations-wrapper">
        <CometChatConversations
          onItemClick={(activeItem) => {
            let item: any = 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>
  );
}
How it works:
  • Init and login happen inside useEffect — the component only renders chat UI after login resolves.
  • When a conversation is tapped, the User or Group is extracted from the Conversation object.
  • selectedUser / selectedGroup state drives which chat is displayed — pass either user or group to the message components, never both.

Step 2 — Render the Astro Page

Import the island and hydrate it client-side using client:only="react".
src/pages/index.astro
---
import ChatApp from "../components/ChatApp.tsx";
import "../styles/globals.css";
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>CometChat + Astro</title>
  </head>
  <body>
    <ChatApp client:only="react" />
  </body>
</html>
The client:only="react" directive ensures the component skips SSR entirely and only renders in the browser — required because CometChat needs window and WebSocket.

Step 3 — Run the Project

npm run dev
You should see the conversation list on the left. Tap any conversation to load messages on the right.

Next Steps