> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-feature-react-native-sdk-quotedmessage-a.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Building a Conversation List + Message View in Astro

The Conversation List + Message View layout provides a familiar two‑panel experience, similar to WhatsApp Web or Slack. Users browse conversations on the left and chat in real time on the right.

***

## User Interface Overview

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b/-YC7tOebleeoFejE/images/e6411d13-chat_experience_sidebar_message-35c431d8bf694e5690e4e0f3a74165af.png?fit=max&auto=format&n=-YC7tOebleeoFejE&q=85&s=03a9df5c80f787357ebc4508839a88cb" alt="Two-panel conversation list and message view" />
</Frame>

This layout includes:

1. Sidebar (Conversation List) – Users and groups
2. Message View – Real-time messages for the selected conversation
3. Message Composer – Input for sending text and media

***

## Prerequisites

* Astro project set up
* React integration added to Astro
* CometChat credentials

<Steps>
  <Step title="Create or open an Astro project">
    <Tabs>
      <Tab title="npm">
        ```bash theme={null}
        npm create astro@latest
        cd my-astro-app
        npm install
        ```
      </Tab>
    </Tabs>

    <Info>
      If you already have the sample `astro-conversation` project, open it instead.
    </Info>
  </Step>

  <Step title="Add React and install CometChat UI Kit">
    ```bash theme={null}
    npx astro add react
    npm i @cometchat/chat-uikit-react react react-dom
    ```

    Add your CometChat credentials to `.env` at the project root:

    ```bash theme={null}
    PUBLIC_COMETCHAT_APP_ID=your_app_id
    PUBLIC_COMETCHAT_REGION=your_region
    PUBLIC_COMETCHAT_AUTH_KEY=your_auth_key
    # Optional: default login UID for development
    PUBLIC_COMETCHAT_LOGIN_UID=cometchat-uid-3
    ```

    <Warning>
      Use Auth Tokens in production instead of Auth Keys.
    </Warning>
  </Step>

  <Step title="Initialize CometChat (src/lib/cometchat-init.js)">
    Create `src/lib/cometchat-init.js` and initialize the UI Kit using environment variables.

    ```javascript src/lib/cometchat-init.js theme={null}
    import { CometChatUIKit, UIKitSettingsBuilder } from "@cometchat/chat-uikit-react";

    const APP_ID   = import.meta.env.PUBLIC_COMETCHAT_APP_ID;
    const REGION   = import.meta.env.PUBLIC_COMETCHAT_REGION;
    const AUTH_KEY = import.meta.env.PUBLIC_COMETCHAT_AUTH_KEY;

    export async function initCometChat() {
      if (!APP_ID || !REGION || !AUTH_KEY) {
        throw new Error("Missing PUBLIC_COMETCHAT_* env vars.");
      }

      const settings = new UIKitSettingsBuilder()
        .setAppId(APP_ID)
        .setRegion(REGION)
        .setAuthKey(AUTH_KEY) // use Auth Tokens in prod
        .subscribePresenceForAllUsers()
        .build();

      await CometChatUIKit.init(settings);
    }

    export async function ensureLogin(uid) {
      const existing = await CometChatUIKit.getLoggedinUser();
      
      // If a different user is logged in, logout first
      if (existing && existing.getUid() !== uid) {
        console.log(`Switching from user ${existing.getUid()} to ${uid}`);
        await CometChatUIKit.logout();
      }
      
      // Login if no user is logged in or we just logged out
      const currentUser = await CometChatUIKit.getLoggedinUser();
      if (!currentUser) {
        await CometChatUIKit.login(uid);
        console.log(`Logged in as user: ${uid}`);
      } else {
        console.log(`Already logged in as user: ${uid}`);
      }
    }

    export async function logout() {
      await CometChatUIKit.logout();
    }
    ```
  </Step>

  <Step title="Build the React island (src/components/ChatApp.jsx)">
    Create the island used by Astro to render the two‑panel chat. This component mirrors the sample in `astro-conversation`.

    ```javascript src/components/ChatApp.jsx theme={null}
    import { useEffect, useState } from "react";
    import {
      CometChatConversations,
      CometChatMessageHeader,
      CometChatMessageList,
      CometChatMessageComposer,
    } from "@cometchat/chat-uikit-react";
    import "@cometchat/chat-uikit-react/css-variables.css";
    import { initCometChat, ensureLogin } from "../lib/cometchat-init.js";

    const LOGIN_UID = "cometchat-uid-3";

    export default function ChatApp() {
      const [phase, setPhase] = useState("boot"); // boot | ready | error
      const [errorMsg, setErrorMsg] = useState("");
      const [selectedUser, setSelectedUser] = useState(null);
      const [selectedGroup, setSelectedGroup] = useState(null);

      useEffect(() => {
        let cancelled = false;
        (async () => {
          try {
            console.log(`Initializing CometChat and logging in as: ${LOGIN_UID}`);
            await initCometChat();
            await ensureLogin(LOGIN_UID);

            if (!cancelled) setPhase("ready");
          } catch (e) {
            console.error("CometChat init/login error:", e);
            if (!cancelled) {
              setErrorMsg(String(e?.message || e));
              setPhase("error");
            }
          }
        })();

        return () => { cancelled = true; };
      }, []);

      const handleConversationClick = (activeItem) => {
        const maybeConv = activeItem?.getConversationWith ? activeItem.getConversationWith() : null;
        const item = maybeConv || activeItem;

        if (item?.getUid) {          // user
          setSelectedUser(item);
          setSelectedGroup(null);
        } else if (item?.getGuid) {  // group
          setSelectedGroup(item);
          setSelectedUser(null);
        } else {
          setSelectedUser(null);
          setSelectedGroup(null);
        }
      };

      if (phase === "boot") return <div style={{ padding: 16 }}>Loading chat…</div>;
      if (phase === "error") {
        return (
          <div style={{ padding: 16, color: "crimson" }}>
            <b>CometChat error:</b> {errorMsg}
          </div>
        );
      }

      return (
        <div className="conversations-with-messages">
          {/* LEFT: conversations */}
          <div className="conversations-wrapper">
            <CometChatConversations onItemClick={handleConversationClick} />
          </div>

          {/* RIGHT: header + list (scrolling) + composer */}
          <div className="messages-wrapper">
            {selectedUser || selectedGroup ? (
              <>
                <CometChatMessageHeader user={selectedUser} group={selectedGroup} />

                <div className="message-list-slot">
                  <CometChatMessageList user={selectedUser} group={selectedGroup} />
                </div>

                <CometChatMessageComposer user={selectedUser} group={selectedGroup} />
              </>
            ) : (
              <div className="empty-conversation">Select a conversation to start</div>
            )}
          </div>
        </div>
      );
    }
    ```
  </Step>

  <Step title="Render the page (src/pages/index.astro)">
    Import the island and styles, then hydrate the component on the client.

    ```astro src/pages/index.astro theme={null}
    ---
    import ChatApp from "../components/ChatApp.jsx";
    import "../styles/globals.css";
    import "../styles/cometchat-layout.css";
    ---

    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>CometChat + Astro</title>
      </head>
      <body>
        <ChatApp client:only="react" />
      </body>
    </html>
    ```

    <Info>
      The CSS files `globals.css` and `cometchat-layout.css` are included in the sample. Ensure your layout CSS sets a two‑panel flex container and sizes the sidebar.
    </Info>
  </Step>

  <Step title="Run and verify">
    ```bash theme={null}
    npm run dev
    ```

    <Check>
      Open your app and verify you can select conversations on the left and exchange messages on the right.
    </Check>
  </Step>
</Steps>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Blank screen or hydration error">
    Ensure the component is rendered as a React island (`client:only=\"react\"`) so it runs only in the browser.
  </Accordion>

  <Accordion title="Missing credentials error">
    Verify `.env` contains `PUBLIC_COMETCHAT_APP_ID`, `PUBLIC_COMETCHAT_REGION`, and `PUBLIC_COMETCHAT_AUTH_KEY`, and restart the dev server after changes.
  </Accordion>

  <Accordion title="Wrong user logged in">
    The sample uses `ensureLogin(uid)` to switch users by logging out if the active UID differs. Update `PUBLIC_COMETCHAT_LOGIN_UID` for development.
  </Accordion>
</AccordionGroup>

***

## Next Steps

* Customize styles in `src/styles/cometchat-layout.css`
* Add presence or typing indicators
* Explore themes and component overrides in the UI Kit

<Tip>
  To build other experiences (One‑to‑One or Tab‑based), reuse `src/lib/cometchat-init.js` and switch the React island component.
</Tip>
