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
This layout consists of:
- Sidebar (Conversation List) – Displays recent conversations with active users and groups.
- Message View – Shows the selected chat with real-time messages.
- 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
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()
    }
}
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
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
Make sure you’ve added the Calls SDK dependency to enable voice and video calling features.
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
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
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:
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:
Ensure you’ve added the necessary permissions and initialized CometChat in your Application class.
Next Steps
Enhance the User Experience