Skip to main content
Version: v5

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.


User Interface Preview

Image

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 TabbedActivity inside your src directory and add the following files:

src/main/java/your-package-name/
├── TabbedActivity.kt
├── ChatsFragment.kt
├── CallLogsFragment.kt
├── UsersFragment.kt
├── GroupsFragment.kt

src/main/java/your-package-name/
├── res/
│ ├── layout/
│ │ ├── activity_tabbed.xml
│ │ ├── fragment_chats.xml
│ │ ├── fragment_call_logs.xml
│ │ ├── fragment_users.xml
│ │ └── fragment_groups.xml
│ └── menu/
│ └── bottom_nav_menu.xml

Download the Icons

These icons are available in the CometChat UI Kit res folder. You can find them at:
🔗 GitHub Assets Folder

Implementation

TabbedActivity.kt
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment

import com.google.android.material.bottomnavigation.BottomNavigationView

class TabbedActivity : AppCompatActivity() {

private lateinit var bottomNavigationView: BottomNavigationView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_tabbed)

setupWindowInsets()
initViews()
setupNavigation(savedInstanceState)
}

private fun setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
}

private fun initViews() {
bottomNavigationView = findViewById(R.id.bottomNavigationView)
}

private fun setupNavigation(savedInstanceState: Bundle?) {
bottomNavigationView.setOnItemSelectedListener { item ->
val fragment = createFragmentForNavItem(item.itemId)
replaceFragment(fragment)
true
}

// Set default fragment only when activity is first created
if (savedInstanceState == null) {
replaceFragment(ChatsFragment())
bottomNavigationView.selectedItemId = R.id.nav_chats
}
}

private fun createFragmentForNavItem(itemId: Int): Fragment {
return when (itemId) {
R.id.nav_chats -> ChatsFragment()
R.id.nav_call_logs -> CallLogsFragment()
R.id.nav_users -> UsersFragment()
R.id.nav_groups -> GroupsFragment()
else -> ChatsFragment()
}
}

private fun replaceFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, fragment)
.commit()
}
}
warning

You must use an activity that supports the lifecycle API, such as:

  • AppCompatActivity
  • ComponentActivity
  • FragmentActivity

This is necessary to properly manage the UI Kit's lifecycle events.


Step 3: Create Fragments for Chat, Calls, Users and Groups

Chats Fragment

ChatsFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class ChatsFragment : Fragment() {

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_chats, container, false)
}
}

Call Logs Fragment

Note

Make sure you’ve added the Calls SDK dependency to enable voice and video calling features.

CallLogsFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class CallLogsFragment : Fragment() {

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_call_logs, container, false)
}
}

Users Fragment

UsersFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class UsersFragment : Fragment() {

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_users, container, false)
}
}

Groups Fragment

GroupsFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class GroupsFragment : Fragment() {

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_groups, container, false)
}
}

Step 3: Update MainActivity

Update the MainActivity to navigate to the MessageActivity:

MainActivity.kt
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.enableEdgeToEdge
import com.cometchat.chat.core.CometChat
import com.cometchat.chat.exceptions.CometChatException
import com.cometchat.chat.models.User
import com.cometchat.chatuikit.shared.cometchatuikit.CometChatUIKit
import com.cometchat.chatuikit.shared.cometchatuikit.UIKitSettings

class MainActivity : ComponentActivity() {

private val TAG = "MainActivity"

private val appID = "APP_ID" // Replace with your App ID
private val region = "REGION" // Replace with your App Region
private val authKey = "AUTH_KEY" // Replace with your Auth Key or leave blank if you are authenticating using Auth Token

private val uiKitSettings = UIKitSettings.UIKitSettingsBuilder()
.setRegion(region)
.setAppId(appID)
.setAuthKey(authKey)
.subscribePresenceForAllUsers()
.build()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()

CometChatUIKit.init(this, uiKitSettings, object : CometChat.CallbackListener<String?>() {
override fun onSuccess(successString: String?) {

Log.d(TAG, "Initialization completed successfully")

loginUser()
}

override fun onError(e: CometChatException?) {}
})
}

private fun loginUser() {
CometChatUIKit.login("cometchat-uid-1", object : CometChat.CallbackListener<User>() {
override fun onSuccess(user: User) {

// Launch Tab-Based Chat Experience (Chats, Calls, Users, Groups)
startActivity(Intent(this@MainActivity, TabbedActivity::class.java))
}

override fun onError(e: CometChatException) {
// Handle login failure (e.g. show error message or retry)
Log.e("Login", "Login failed: ${e.message}")
}
})
}
}

Running the Project

Once the components are configured, build and run the app:

gradle build

Ensure you've added the necessary permissions and initialized CometChat in your Application class.


Next Steps

Enhance the User Experience