Documentation Index Fetch the complete documentation index at: https://cometchat-22654f5b-react-uikit-v7.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
AI Integration Quick Reference
Field Value Package @cometchat/chat-uikit-reactFramework Next.js (App Router) Components CometChatConversations, CometChatCallLogs, CometChatUsers, CometChatMessageHeader, CometChatMessageList, CometChatMessageComposerLayout Tabbed sidebar (Chat, Calls, Users) + message view Prerequisite Complete Next.js Integration first SSR Component loaded with dynamic(() => import(...), { ssr: false }) Pattern Full-featured messaging app with multiple sections
This guide builds a tabbed messaging UI — Chat, Calls, and Users tabs in the sidebar, with a message view on the right. Good for full-featured apps that need more than just conversations.
This assumes you’ve already completed Next.js Integration (project created, UI Kit installed, init + login working).
What You’re Building
Three sections working together:
Tab bar — switches between Chat, Calls, and Users
Sidebar — renders the list for the active tab
Message view — header + messages + composer for the selected item
Full Code
Create the client component with the tabbed UI, then import it dynamically in your page.
app/chat/CometChatClient.tsx
'use client' ;
import { useState } from "react" ;
import { CometChat } from "@cometchat/chat-sdk-javascript" ;
import {
CometChatProvider ,
CometChatConversations ,
CometChatUsers ,
CometChatCallLogs ,
CometChatMessageHeader ,
CometChatMessageList ,
CometChatMessageComposer ,
} from "@cometchat/chat-uikit-react" ;
import "@cometchat/chat-uikit-react/styles" ;
type Tab = "chat" | "calls" | "users" ;
export default function CometChatClient () {
const [ activeTab , setActiveTab ] = useState < Tab >( "chat" );
const [ selectedUser , setSelectedUser ] = useState < CometChat . User | undefined >( undefined );
const [ selectedGroup , setSelectedGroup ] = useState < CometChat . Group | undefined >( undefined );
const handleConversationClick = ( conversation : CometChat . Conversation ) => {
const entity = conversation . getConversationWith ();
if ( conversation . getConversationType () === "user" ) {
setSelectedUser ( entity as CometChat . User );
setSelectedGroup ( undefined );
} else {
setSelectedGroup ( entity as CometChat . Group );
setSelectedUser ( undefined );
}
};
const handleUserClick = ( user : CometChat . User ) => {
setSelectedUser ( user );
setSelectedGroup ( undefined );
};
const handleCallClick = ( call : any ) => {
const initiator = call . getInitiator ();
const receiver = call . getReceiver ();
// Determine the other party in the call
if ( receiver instanceof CometChat . User ) {
setSelectedUser ( receiver );
setSelectedGroup ( undefined );
} else if ( receiver instanceof CometChat . Group ) {
setSelectedUser ( undefined );
setSelectedGroup ( receiver );
} else if ( initiator instanceof CometChat . User ) {
setSelectedUser ( initiator );
setSelectedGroup ( undefined );
}
};
return (
< CometChatProvider >
< div className = "tabbed-chat" >
< div className = "sidebar" >
< div className = "tab-bar" >
< button
className = { `tab-button ${ activeTab === "chat" ? "tab-button--active" : "" } ` }
onClick = { () => setActiveTab ( "chat" ) }
>
Chats
</ button >
< button
className = { `tab-button ${ activeTab === "calls" ? "tab-button--active" : "" } ` }
onClick = { () => setActiveTab ( "calls" ) }
>
Calls
</ button >
< button
className = { `tab-button ${ activeTab === "users" ? "tab-button--active" : "" } ` }
onClick = { () => setActiveTab ( "users" ) }
>
Users
</ button >
</ div >
< div className = "sidebar-list" >
{ activeTab === "chat" && (
< CometChatConversations onItemClick = { handleConversationClick } />
) }
{ activeTab === "calls" && (
< CometChatCallLogs onItemClick = { handleCallClick } />
) }
{ activeTab === "users" && (
< CometChatUsers onItemClick = { handleUserClick } />
) }
</ div >
</ 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 >
</ CometChatProvider >
);
}
.tabbed-chat {
display : flex ;
height : 100 vh ;
width : 100 % ;
}
.sidebar {
width : 360 px ;
height : 100 % ;
display : flex ;
flex-direction : column ;
border-right : 1 px solid #eee ;
}
.tab-bar {
display : flex ;
border-bottom : 1 px solid #eee ;
background : var ( --cometchat-background-color-01 , #fff );
}
.tab-button {
flex : 1 ;
padding : 12 px 0 ;
border : none ;
background : none ;
cursor : pointer ;
font : var ( --cometchat-font-body-medium , 500 14 px Roboto);
color : var ( --cometchat-text-color-secondary , #727272 );
border-bottom : 2 px solid transparent ;
transition : color 0.2 s , border-color 0.2 s ;
}
.tab-button:hover {
color : var ( --cometchat-text-color-primary , #141414 );
}
.tab-button--active {
color : var ( --cometchat-text-color-highlight , #6851d6 );
border-bottom-color : var ( --cometchat-primary-color , #6851d6 );
}
.sidebar-list {
flex : 1 ;
overflow : hidden ;
display : flex ;
flex-direction : column ;
}
.messages-wrapper {
flex : 1 ;
height : 100 % ;
display : flex ;
flex-direction : column ;
}
.empty-conversation {
flex : 1 ;
display : flex ;
justify-content : center ;
align-items : center ;
background : var ( --cometchat-background-color-03 , #f5f5f5 );
color : var ( --cometchat-text-color-secondary , #727272 );
font : var ( --cometchat-font-body-regular , 400 14 px Roboto);
}
import dynamic from 'next/dynamic' ;
const CometChatClient = dynamic (() => import ( './CometChatClient' ), { ssr: false });
export default function ChatPage () {
return < CometChatClient /> ;
}
How It Works
'use client' marks the component as a Client Component — required because CometChat uses browser APIs.
dynamic(() => import(...), { ssr: false }) prevents the component from rendering on the server.
Tab state — activeTab controls which list component renders in the sidebar.
Conditional rendering — only the active tab’s component mounts. Switching tabs unmounts the previous list and mounts the new one.
Unified selection — all three tabs feed into the same selectedUser / selectedGroup state. Clicking any item (conversation, call log, or user) updates the message panel.
Call log handling — when a call log is clicked, the receiver (user or group) is extracted and passed to the message components.
Adding More Tabs
To add a Groups tab, import CometChatGroups and add another tab button + conditional render:
import { CometChatGroups } from "@cometchat/chat-uikit-react" ;
// Add to Tab type:
type Tab = "chat" | "calls" | "users" | "groups" ;
// Add button in tab-bar:
< button
className = { `tab-button ${ activeTab === "groups" ? "tab-button--active" : "" } ` }
onClick = { () => setActiveTab ( "groups" ) }
>
Groups
</ button >
// Add in sidebar-list:
{ activeTab === "groups" && (
< CometChatGroups
onItemClick = { ( group : CometChat . Group ) => {
setSelectedGroup ( group );
setSelectedUser ( undefined );
} }
/>
)}
You can follow the same pattern for any additional tabs (Settings, Contacts, etc.).
Run
Open http://localhost:3000/chat. You should see the tab bar at the top of the sidebar. Switch between Chats, Calls, and Users — clicking any item loads the message view on the right.
Next Steps
Conversation List + Messages Two-panel layout without tabs
Components Overview Browse all prebuilt UI components
Theming Customize colors, fonts, and styles