> ## 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 Messaging UI With Tabs, Sidebar, And Message View

This guide walks you through creating a **tab-based messaging UI** using **React** and **CometChat UIKit**. The UI will include different sections for **Chats, Calls, Users, and Groups**, allowing seamless navigation.

[<img src="https://mintcdn.com/cometchat-22654f5b-feature-react-native-sdk-quotedmessage-a/R-mrzo_AxVZMXils/images/30d34521-play-codesandbox.svg?fit=max&auto=format&n=R-mrzo_AxVZMXils&q=85&s=719f2f667589e0991584e435e7936741" width="165" height="32" data-path="images/30d34521-play-codesandbox.svg" />](https://link.cometchat.com/next-tabs-sidebar-message)

> **Tip:** You can **fork** the sandbox, insert your **CometChat credentials** (App ID, Region, Auth Key.) in the code, and immediately preview how the UI and messages respond in real time.

***

## **User Interface Preview**

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-react-native-sdk-quotedmessage-a/FOPcIvXNMzgmVa9j/images/010808a2-multi_tab_ui_web_screens-4c6055da929b73c11d7d45b0112fd5fc.png?fit=max&auto=format&n=FOPcIvXNMzgmVa9j&q=85&s=25e2a8b035f8f0d92dc72339ade2c54c" width="1282" height="802" data-path="images/010808a2-multi_tab_ui_web_screens-4c6055da929b73c11d7d45b0112fd5fc.png" />
</Frame>

This layout consists of:

1. **Sidebar (Conversation List)** – Displays recent conversations with active users and groups.
2. **Message View** – Shows the selected chat with real-time messages.
3. **Message Input Box** – Allows users to send messages seamlessly.

***

## **Step-by-Step Guide**

### **Step 1: Create a Tab Component**

To manage navigation, let's build a **`CometChatTabs`** component. This component will render different tabs and allow switching between sections dynamically.

#### **Folder Structure**

Create a `CometChatTabs` folder inside your `src` directory and add the following files:

```php theme={null}
public/
├── assets # These are the images you need to save
│   ├── chats.svg 
│   ├── calls.svg 
│   ├── users.svg 
│   ├── groups.svg
src/
│── 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](https://github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/assets)

***

#### **Implementation**

<Tabs>
  <Tab title="TypeScript">
    ```tsx CometChatTabs.tsx theme={null}
    import { useState } from "react";
    import "./CometChatTabs.css";

    // Define icon paths for each tab
    const chatsIcon = "/assets/chats.svg";
    const callsIcon = "/assets/calls.svg";
    const usersIcon = "/assets/users.svg";
    const groupsIcon = "/assets/groups.svg";

    // CometChatTabs component to display tab options
    export const CometChatTabs = (props: {
      onTabClicked?: (tabItem: { name: string; icon?: string }) => void; // Callback when a tab is clicked
      activeTab?: string; // Name of the currently active tab
    }) => {
      // Destructure props with default fallback
      const {
        onTabClicked = () => {}, // Fallback to no-op if not provided
        activeTab,
      } = props;

      // State to track the currently hovered tab
      const [hoverTab, setHoverTab] = useState("");

      // Array of tab items with their labels and icons
      const tabItems = [
        { name: "CHATS", icon: chatsIcon },
        { name: "CALLS", icon: callsIcon },
        { name: "USERS", icon: usersIcon },
        { name: "GROUPS", icon: groupsIcon },
      ];

      return (
        <div className="cometchat-tab-component">
          {/* Loop through each tab item to render it */}
          {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)} // Invoke callback on click
              >
                {/* Icon section with mask styling */}
                <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("")}
                />

                {/* Tab label */}
                <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>
      );
    };
    ```
  </Tab>

  <Tab title="CSS">
    ```css CometChatTabs.css theme={null}
    /* Main container for the CometChat tab bar */
    .cometchat-tab-component {
      display: flex; /* Align child tabs horizontally */
      width: 100%; /* Full-width tab bar */
      padding: 0px 8px; /* Horizontal padding */
      align-items: flex-start; /* Align tab items to the top */
      gap: 8px; /* Space between tab items */
      border-top: 1px solid var(--cometchat-border-color-light, #F5F5F5); /* Top border */
      border-right: 1px solid var(--cometchat-border-color-light, #F5F5F5); /* Right border */
      background: var(--cometchat-background-color-01, #FFF); /* Background color */
    }

    /* Styles for each individual tab */
    .cometchat-tab-component__tab {
      display: flex;
      flex-direction: column; /* Stack icon and text vertically */
      justify-content: center; /* Center vertically */
      align-items: center; /* Center horizontally */
      padding: 12px 0px 10px 0px; /* Top and bottom spacing */
      gap: 4px; /* Space between icon and text */
      flex: 1 0 0; /* Equally distribute available space among tabs */
      min-height: 48px; /* Minimum height for consistent layout */
    }

    /* Default tab icon style */
    .cometchat-tab-component__tab-icon {
      display: flex;
      width: 32px;
      height: 32px;
      justify-content: center;
      align-items: center;
      background: var(--cometchat-icon-color-secondary); /* Default icon background */
      -webkit-mask-size: contain;
      -webkit-mask-position: center;
      -webkit-mask-repeat: no-repeat;
      mask-size: contain;
      mask-position: center;
      mask-repeat: no-repeat;
      cursor: pointer;
    }

    /* Tab text label style */
    .cometchat-tab-component__tab-text {
      color: var(--cometchat-text-color-secondary, #727272); /* Default label color */
      text-align: center;
      font: var(--cometchat-font-caption1-medium, 500 12px Roboto); /* Font style */
      cursor: pointer;
    }

    /* Highlighted icon style for active/hovered tab */
    .cometchat-tab-component__tab-icon-active {
      background: var(--cometchat-icon-color-highlight); /* Highlight color */
    }

    /* Highlighted text style for active/hovered tab */
    .cometchat-tab-component__tab-text-active {
      color: var(--cometchat-text-color-highlight); /* Highlighted text color */
    }
    ```
  </Tab>
</Tabs>

***

### **Step 2: Create Sidebar**

Let's create the `Sidebar` component which will render different conversations.

#### **Folder Structure**

Create a `CometChatSelector` folder inside your `src/app` directory and add the following files:

```
src/
│── CometChatSelector/ 
│   ├── CometChatSelector.tsx
│   ├── CometChatSelector.css
```

<Tabs>
  <Tab title="TypeScript">
    ```tsx CometChatSelector.tsx theme={null}
    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";

    // Define props interface for selector
    interface SelectorProps {
      onSelectorItemClicked?: (input: User | Group | Conversation | Call, type: string) => void;
    }

    export const CometChatSelector = (props: SelectorProps) => {
      const {
        onSelectorItemClicked = () => {},
      } = props;

      // State to manage currently logged in user
      const [loggedInUser, setLoggedInUser] = useState<CometChat.User | null>();

      // State to track selected conversation, user, group, or call
      const [activeItem, setActiveItem] = useState<
        Conversation | User | Group | Call | undefined
      >();

      // State to track currently active tab: "chats", "calls", "users", or "groups"
      const [activeTab, setActiveTab] = useState<string>("chats");

      // Fetch logged-in user once component mounts
      useEffect(() => {
        const user = CometChatUIKitLoginListener.getLoggedInUser();
        setLoggedInUser(user);
      }, [CometChatUIKitLoginListener?.getLoggedInUser()]);

      // Logout function to clear user session
      const logOut = () => {
        CometChatUIKit.logout()
          .then(() => {
            setLoggedInUser(null);
          })
          .catch((error) => {
            console.log("Logout error:", error);
          });
      };

      return (
        <>
          {/* Render selector content only if a user is logged in */}
          {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");
                  }}
                />
              )}
            </>
          )}

          {/* Render the tab switcher at the bottom */}
          <CometChatTabs
            activeTab={activeTab}
            onTabClicked={(item) => {
              setActiveTab(item.name.toLowerCase()); // Update tab on click
            }}
          />
        </>
      );
    };
    ```
  </Tab>

  <Tab title="CSS">
    ```css CometChatSelector.css theme={null}
    /* Style the icon inside header menu in conversation list */
    .selector-wrapper .cometchat-conversations .cometchat-list__header-menu .cometchat-button__icon {
      background: var(--cometchat-icon-color-primary); /* Primary icon color */
    }

    /* Highlight icon on hover */
    .cometchat-conversations .cometchat-list__header-menu .cometchat-button__icon:hover {
      background: var(--cometchat-icon-color-highlight); /* Highlighted icon color on hover */
    }

    /* Remove right border from the search bar inside the list */
    .cometchat-list__header-search-bar {
      border-right: none;
    }

    /* Align menu list items to the left */
    .cometchat .cometchat-menu-list__sub-menu-list-item {
      text-align: left;
    }

    /* Positioning for the submenu inside conversations menu */
    .cometchat .cometchat-conversations .cometchat-menu-list__sub-menu-list {
      width: 212px;
      top: 40px !important;
      left: 172px !important;
    }

    /* Style for the logged-in user section with bottom border */
    #logged-in-user {
      border-bottom: 2px solid var(--cometchat-border-color-default, #E8E8E8);
    }

    /* Make submenu items under logged-in user non-clickable */
    #logged-in-user .cometchat-menu-list__sub-menu-item-title,
    #logged-in-user .cometchat-menu-list__sub-menu-list-item {
      cursor: default;
    }

    /* Logout icon color inside submenu */
    .cometchat-menu-list__sub-menu-list-item-icon-log-out {
      background-color: var(--cometchat-error-color, #F44649); /* Error color */
    }

    /* Logout label/text color inside submenu */
    .cometchat-menu-list__sub-menu-item-title-log-out {
      color: var(--cometchat-error-color, #F44649);
    }

    /* Enable pointer cursor for chat menu item titles */
    .chat-menu .cometchat .cometchat-menu-list__sub-menu-item-title {
      cursor: pointer;
    }

    /* Remove shadow from the chat menu's submenu */
    .chat-menu .cometchat .cometchat-menu-list__sub-menu {
      box-shadow: none;
    }

    /* Style the icons inside chat menu items */
    .chat-menu .cometchat .cometchat-menu-list__sub-menu-icon {
      background-color: var(--cometchat-icon-color-primary, #141414);
      width: 24px;
      height: 24px;
    }
    ```
  </Tab>
</Tabs>

### **Step 3: Render Experience**

Now we will update the `CometChatNoSSR.tsx` & `CometChatNoSSR.css` files to import these new components as below,

<Tabs>
  <Tab title="TypeScript">
    ```tsx CometChatNoSSR.tsx theme={null}
    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";

    // Constants for CometChat configuration
    const COMETCHAT_CONSTANTS = {
      APP_ID: "",
      REGION: "",
      AUTH_KEY: "",
    };

    // Functional component for CometChatNoSSR
    const CometChatNoSSR: React.FC = () => {
      // State to store the logged-in user
      const [user, setUser] = useState<CometChat.User | undefined>(undefined);
      // State to store selected user or group
      const [selectedUser, setSelectedUser] = useState<CometChat.User | undefined>(undefined);
      const [selectedGroup, setSelectedGroup] = useState<CometChat.Group | undefined>(undefined);

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

        // Initialize CometChat UIKit
        CometChatUIKit.init(UIKitSettings)
          ?.then(() => {
            console.log("Initialization completed successfully");
            // Check if user is already logged in
            CometChatUIKit.getLoggedinUser().then((loggedInUser) => {
              if (!loggedInUser) {
                // Perform login if no user is logged in
                CometChatUIKit.login("cometchat-uid-4")
                  .then((user) => {
                    console.log("Login Successful", { user });
                    setUser(user);
                  })
                  .catch((error) => console.error("Login failed", error));
              } else {
                console.log("Already logged-in", { loggedInUser });
                setUser(loggedInUser);
              }
            });
          })
          .catch((error) => console.error("Initialization failed", error));
      }, []);

      return user ? (
        <div className="conversations-with-messages">
          {/* Sidebar with conversation list */}
          <div className="conversations-wrapper">
            <CometChatSelector 
              onSelectorItemClicked={(activeItem) => {
                let item = activeItem;
                // Extract the conversation participant
                if (activeItem instanceof CometChat.Conversation) {
                  item = activeItem.getConversationWith();
                } 
                // Update states based on the type of selected item
                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>
          
          {/* Message view section */}
          {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;
    ```
  </Tab>

  <Tab title="CSS">
    ```css CometChatNoSSR.css theme={null}
    /* Layout for the main container that holds conversations and messages */
    .conversations-with-messages {
        display: flex;
        height: 100%;
        width: 100%;
    }

    /* Sidebar wrapper for conversation list */
    .conversations-wrapper {
        height: 100%;
        width: 480px; /* Fixed width for conversation list */
        overflow: hidden; /* Hide any overflowing content */
        display: flex;
        flex-direction: column;
        height: inherit;
    }

    /* Hide overflow content inside the conversation component */
    .conversations-wrapper > .cometchat {
        overflow: hidden;
    }

    /* Message section layout */
    .messages-wrapper {
        width: calc(100% - 480px); /* Take remaining space */
        height: 100%;
        display: flex;
        flex-direction: column;
    }

    /* Styling for when no conversation is selected */
    .empty-conversation {
        height: 100%;
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        background: white;
        color: var(--cometchat-text-color-secondary, #727272);
        font: var(--cometchat-font-body-regular, 400 14px Roboto);
    }

    /* Ensure message composer does not have rounded corners */
    .cometchat .cometchat-message-composer {
        border-radius: 0px;
    }
    ```
  </Tab>
</Tabs>

### **Step 4: Disabling SSR for `CometChatNoSSR.tsx` in Next.js**

In this update, we will **disable Server-Side Rendering (SSR) for `CometChatNoSSR.tsx`** while keeping the rest of the application’s SSR functionality intact. This ensures that the **CometChat UI Kit components load only on the client-side**, preventing SSR-related issues.

#### **Disabling SSR in `index.tsx`**

Modify your `index.tsx` file to dynamically import the `CometChatNoSSR.tsx` component with `{ ssr: false }`.

```tsx index.tsx theme={null}
import { Inter } from "next/font/google";
import dynamic from "next/dynamic";

import '@cometchat/chat-uikit-react/css-variables.css';

const inter = Inter({ subsets: ["latin"] });

// Dynamically import CometChat component with SSR disabled
const CometChatComponent = dynamic(() => import("../CometChatNoSSR/CometChatNoSSR"), {
  ssr: false,
});

export default function Home() {
  return <CometChatComponent />;
}
```

#### **Why disable SSR?**

* The CometChat UI Kit depends on browser APIs (window, document, WebSockets).
* Next.js pre-renders components on the server, which can cause errors with browser-specific features.
* By setting `{ ssr: false }`, we ensure that CometChatNoSSR.tsx only loads on the client.

### **Step 5: Update Global CSS**

Next, add the following styles to global.css to ensure CometChat UI Kit is properly styled.

```css global.css theme={null}
:root {
  --background: #ffffff;
  --foreground: #171717;
}

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

/** Give your App a height of `100%`. Keep other CSS properties in the below selector as it is. */
.root {
  height: 100%;
}

#__next {
  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;
  }
}
```

### **Step 6: Run the project**

```
npm run dev
```

***

## **Next Steps**

### **Enhance the User Experience**

* **[Advanced Customizations](/ui-kit/react/theme)** – Personalize the chat UI to align with your brand.

***
