Skip to main content
CometChatUsers renders a scrollable list of all available users with real-time presence updates, search, avatars, and online/offline status indicators.

Where It Fits

CometChatUsers is a list component. It renders all available users and emits the selected User via onItemClick. Wire it to CometChatMessageHeader, CometChatMessageList, and CometChatMessageComposer to build a direct messaging layout.
activity_chat.xml
<com.cometchat.uikit.kotlin.presentation.users.ui.CometChatUsers
    android:id="@+id/users"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
val users = findViewById<CometChatUsers>(R.id.users)

users.setOnItemClick { user ->
    messageHeader.setUser(user)
    messageList.setUser(user)
    messageComposer.setUser(user)
}

Quick Start

Add to your layout XML:
<com.cometchat.uikit.kotlin.presentation.users.ui.CometChatUsers
    android:id="@+id/users"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Or programmatically:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(CometChatUsers(this))
}
Prerequisites: CometChat SDK initialized with CometChatUIKit.init(), a user logged in, and the UI Kit dependency added. Or in a Fragment:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
    return CometChatUsers(requireContext())
}

Filtering Users

Pass a UsersRequest.UsersRequestBuilder to control what loads:
users.setUsersRequestBuilder(
    UsersRequest.UsersRequestBuilder()
        .friendsOnly(true)
        .setLimit(20)
)

Filter Recipes

RecipeBuilder method
Friends only.friendsOnly(true)
Limit per page.setLimit(10)
Search by keyword.setSearchKeyword("john")
Hide blocked users.hideBlockedUsers(true)
Filter by roles.setRoles(listOf("admin", "moderator"))
Filter by tags.setTags(listOf("vip"))
Online users only.setUserStatus(CometChatConstants.USER_STATUS_ONLINE)
Filter by UIDs.setUIDs(listOf("uid1", "uid2"))
Pass the builder object, not the result of .build(). The component calls .build() internally. Default page size is 30 with infinite scroll.

Actions and Events

Callback Methods

onItemClick

Fires when a user row is tapped. Primary navigation hook.
users.setOnItemClick { user ->
    // Navigate to chat screen
}
Replaces the default item-click behavior. Your custom lambda executes instead of the built-in navigation.

onItemLongClick

Fires when a user row is long-pressed. Use for additional actions like block or mute.
users.setOnItemLongClick { user ->
    // Show context menu
}

onBackPress

Fires when the user presses the back button in the toolbar.
users.setOnBackPress {
    finish()
}

onSearchClick

Fires when the user taps the search icon in the toolbar.
users.setOnSearchClick {
    // Open search screen
}

onSelection

Fires when users are selected/deselected in multi-select mode.
users.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE)
users.setOnSelection { selectedUsers ->
    updateToolbar(selectedUsers.size)
}

onError

Fires on internal errors (network failure, auth issue, SDK exception).
users.setOnError { exception ->
    Log.e("Users", "Error: ${exception.message}")
}

onLoad

Fires when the list is successfully fetched and loaded.
users.setOnLoad { userList ->
    Log.d("Users", "Loaded ${userList.size}")
}

onEmpty

Fires when the list is empty after loading.
users.setOnEmpty {
    Log.d("Users", "No users found")
}

SDK Events (Real-Time, Automatic)

The component listens to these SDK events internally. No manual setup needed.
SDK ListenerInternal behavior
onUserOnlineUpdates online status indicator for the user
onUserOfflineUpdates offline status indicator for the user

Functionality

Method (Kotlin XML)Compose ParameterDescription
setBackIconVisibility(View.VISIBLE)hideBackIcon = falseToggle back button
setToolbarVisibility(View.GONE)hideToolbar = trueToggle toolbar
setSearchBoxVisibility(View.GONE)hideSearchBox = trueToggle search box
setStickyHeaderVisibility(View.GONE)hideStickyHeader = trueToggle alphabetical sticky header
setUserStatusVisibility(View.GONE)hideUserStatus = trueToggle online status indicator
setSeparatorVisibility(View.GONE)hideSeparator = trueToggle list separators
setSelectionMode(MULTIPLE)selectionMode = MULTIPLEEnable selection mode
setTitle("Contacts")title = "Contacts"Custom toolbar title
setSearchPlaceholderText("Find...")searchPlaceholderText = "Find..."Search placeholder

Custom View Slots

Leading View

Replace the avatar / left section.
users.setLeadingView(object : UsersViewHolderListener() {
    override fun createView(context: Context, binding: CometchatListBaseItemsBinding): View {
        return ImageView(context).apply {
            layoutParams = ViewGroup.LayoutParams(48.dp, 48.dp)
        }
    }

    override fun bindView(
        context: Context, createdView: View, user: User,
        holder: RecyclerView.ViewHolder, userList: List<User>, position: Int
    ) {
        val imageView = createdView as ImageView
        // Load avatar image
    }
})

Title View

Replace the name / title text.
users.setTitleView(object : UsersViewHolderListener() {
    override fun createView(context: Context, binding: CometchatListBaseItemsBinding): View {
        return TextView(context)
    }

    override fun bindView(
        context: Context, createdView: View, user: User,
        holder: RecyclerView.ViewHolder, userList: List<User>, position: Int
    ) {
        (createdView as TextView).text = user.name ?: ""
    }
})

Subtitle View

Replace the subtitle text below the user’s name.
users.setSubtitleView(object : UsersViewHolderListener() {
    override fun createView(context: Context, binding: CometchatListBaseItemsBinding): View {
        return TextView(context)
    }

    override fun bindView(
        context: Context, createdView: View, user: User,
        holder: RecyclerView.ViewHolder, userList: List<User>, position: Int
    ) {
        val tvSubtitle = createdView as TextView
        tvSubtitle.text = "Last Active: " + SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(user.lastActiveAt * 1000)
    }
})

Trailing View

Replace the right section of each user item.
users.setTrailingView(object : UsersViewHolderListener() {
    override fun createView(context: Context, binding: CometchatListBaseItemsBinding): View {
        return TextView(context)
    }

    override fun bindView(
        context: Context, createdView: View, user: User,
        holder: RecyclerView.ViewHolder, userList: List<User>, position: Int
    ) {
        (createdView as TextView).text = user.role ?: ""
    }
})

Item View

Replace the entire list item row.
users.setItemView(object : UsersViewHolderListener() {
    override fun createView(context: Context, binding: CometchatListBaseItemsBinding): View {
        return LayoutInflater.from(context).inflate(R.layout.custom_user_item, null)
    }

    override fun bindView(
        context: Context, createdView: View, user: User,
        holder: RecyclerView.ViewHolder, userList: List<User>, position: Int
    ) {
        val avatar = createdView.findViewById<CometChatAvatar>(R.id.custom_avatar)
        val title = createdView.findViewById<TextView>(R.id.tvName)
        title.text = user.name
        avatar.setAvatar(user.name, user.avatar)
    }
})

State Views

users.setEmptyView(R.layout.custom_empty_view)
users.setErrorView(R.layout.custom_error_view)
users.setLoadingView(R.layout.custom_loading_view)

Overflow Menu

users.setOverflowMenu(ImageButton(context).apply {
    setImageResource(R.drawable.ic_filter)
    setOnClickListener { /* show filter */ }
})

// Replace all options
users.setOptions { context, user ->
    listOf(
        CometChatPopupMenu.MenuItem(id = "block", name = "Block", onClick = { /* ... */ }),
        CometChatPopupMenu.MenuItem(id = "mute", name = "Mute", onClick = { /* ... */ })
    )
}

// Append to defaults
users.setAddOptions { context, user ->
    listOf(
        CometChatPopupMenu.MenuItem(id = "pin", name = "Pin", onClick = { /* ... */ })
    )
}

Common Patterns

Minimal list — hide all chrome

users.setToolbarVisibility(View.GONE)
users.setSearchBoxVisibility(View.GONE)
users.setStickyHeaderVisibility(View.GONE)
users.setUserStatusVisibility(View.GONE)

Friends-only list

users.setUsersRequestBuilder(
    UsersRequest.UsersRequestBuilder()
        .friendsOnly(true)
)

Online users only

users.setUsersRequestBuilder(
    UsersRequest.UsersRequestBuilder()
        .setUserStatus(CometChatConstants.USER_STATUS_ONLINE)
)

Advanced Methods

Programmatic Selection

// Enable selection
users.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE)

// Select a user
users.selectUser(user, UIKitConstants.SelectionMode.MULTIPLE)

// Get selected
val selected = users.getSelectedUsers()

// Clear
users.clearSelection()

ViewModel Access

val factory = CometChatUsersViewModelFactory()
val viewModel = ViewModelProvider(this, factory)
    .get(CometChatUsersViewModel::class.java)
users.setViewModel(viewModel)
See ViewModel & Data for ListOperations, state observation, and custom repositories.

Style

Define a custom style in themes.xml:
themes.xml
<style name="CustomAvatarStyle" parent="CometChatAvatarStyle">
    <item name="cometchatAvatarStrokeRadius">8dp</item>
    <item name="cometchatAvatarBackgroundColor">#FBAA75</item>
</style>

<style name="CustomUsersStyle" parent="CometChatUsersStyle">
    <item name="cometchatUsersAvatarStyle">@style/CustomAvatarStyle</item>
    <item name="cometchatUsersSeparatorColor">#F76808</item>
    <item name="cometchatUsersTitleTextColor">#F76808</item>
</style>

<style name="AppTheme" parent="CometChatTheme.DayNight">
    <item name="cometchatUsersStyle">@style/CustomUsersStyle</item>
</style>

Style Properties

PropertyDescription
backgroundColorList background color
titleTextColorToolbar title color
searchBoxStyleSearch box appearance
itemStyle.backgroundColorRow background
itemStyle.selectedBackgroundColorSelected row background
itemStyle.titleTextColorUser name color
itemStyle.subtitleTextColorSubtitle text color
itemStyle.separatorColorRow separator color
itemStyle.avatarStyleAvatar appearance
itemStyle.statusIndicatorStyleOnline/offline indicator
See Component Styling for the full reference.

Next Steps

Conversations

Browse recent conversations

Groups

Browse and search available groups

Component Styling

Detailed styling reference with screenshots

ViewModel & Data

Custom ViewModels, repositories, and ListOperations