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