Skip to main content
{
  "component": "CometChatGroupMembers",
  "package": "com.cometchat.chatuikit.groupmembers",
  "xmlElement": "<com.cometchat.chatuikit.groupmembers.CometChatGroupMembers />",
  "description": "Scrollable list of all members in a group with search, avatars, names, scope badges, and online/offline status indicators. Requires a Group object to be set via setGroup().",
  "primaryOutput": {
    "method": "setOnItemClick",
    "type": "OnItemClick<GroupMember>"
  },
  "methods": {
    "data": {
      "setGroup": {
        "type": "Group",
        "required": true,
        "note": "Must be called before the component can load data"
      },
      "setGroupMembersRequestBuilder": {
        "type": "GroupMembersRequest.GroupMembersRequestBuilder",
        "default": "SDK default",
        "note": "Pass the builder, not the result of .build()"
      },
      "setSearchRequestBuilder": {
        "type": "GroupMembersRequest.GroupMembersRequestBuilder",
        "default": "Same as main builder",
        "note": "Separate builder for search results"
      }
    },
    "callbacks": {
      "setOnItemClick": "OnItemClick<GroupMember>",
      "setOnItemLongClick": "OnItemLongClick<GroupMember>",
      "setOnBackPressListener": "OnBackPress",
      "setOnSelection": "OnSelection<GroupMember>",
      "setOnError": "OnError",
      "setOnLoadMore": "OnLoad<GroupMember>",
      "setOnEmpty": "OnEmpty"
    },
    "visibility": {
      "setBackIconVisibility": { "type": "int (View.VISIBLE | View.GONE)", "default": "View.GONE" },
      "setToolbarVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setLoadingStateVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setErrorStateVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setEmptyStateVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setSeparatorVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setUserStatusVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setSearchBoxVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setKickMemberOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setBanMemberOptionVisibility": { "type": "int", "default": "View.VISIBLE" },
      "setScopeChangeOptionVisibility": { "type": "int", "default": "View.VISIBLE" }
    },
    "selection": {
      "setSelectionMode": {
        "type": "UIKitConstants.SelectionMode",
        "values": ["NONE", "SINGLE", "MULTIPLE"],
        "default": "NONE"
      }
    },
    "viewSlots": {
      "setItemView": "GroupMembersViewHolderListeners — entire list item row",
      "setLeadingView": "GroupMembersViewHolderListeners — avatar / left section",
      "setTitleView": "GroupMembersViewHolderListeners — name / title text",
      "setSubtitleView": "GroupMembersViewHolderListeners — subtitle text below name",
      "setTrailingView": "GroupMembersViewHolderListeners — right section",
      "setLoadingStateView": "@LayoutRes int — loading spinner",
      "setEmptyStateView": "@LayoutRes int — empty state",
      "setErrorStateView": "@LayoutRes int — error state",
      "setOverflowMenu": "View — toolbar menu",
      "setOptions": "Function3<Context, GroupMember, Group, List<MenuItem>> — long-press context menu (replaces defaults)",
      "addOptions": "Function3<Context, GroupMember, Group, List<MenuItem>> — long-press context menu (appends to defaults)"
    },
    "advanced": {
      "selectGroupMember": "GroupMember, SelectionMode — programmatic selection",
      "clearSelection": "void — clears all selected group members",
      "getSelectedGroupMembers": "List<GroupMember> — returns selected items",
      "setSearchKeyword": "String — programmatic search",
      "setTitleText": "String — custom toolbar title",
      "excludeOwner": "boolean — exclude group owner from list",
      "getBinding": "CometchatGroupMembersListViewBinding — root ViewBinding",
      "getViewModel": "GroupMembersViewModel — internal ViewModel access",
      "getAdapter": "GroupMembersAdapter — internal adapter access",
      "setAdapter": "GroupMembersAdapter — replace the default adapter"
    },
    "style": {
      "setStyle": {
        "type": "@StyleRes int",
        "parent": "CometChatGroupMembersStyle"
      }
    }
  },
  "events": [
    {
      "name": "CometChatGroupEvents.ccGroupMemberBanned",
      "payload": "Action, User, User, Group",
      "description": "A group member was banned from the group"
    },
    {
      "name": "CometChatGroupEvents.ccGroupMemberKicked",
      "payload": "Action, User, User, Group",
      "description": "A group member was kicked from the group"
    },
    {
      "name": "CometChatGroupEvents.ccGroupMemberScopeChanged",
      "payload": "Action, User, String, String, Group",
      "description": "A group member's scope was changed"
    },
    {
      "name": "CometChatGroupEvents.ccGroupMemberAdded",
      "payload": "List<Action>, List<User>, Group, User",
      "description": "Members were added to the group"
    },
    {
      "name": "CometChatGroupEvents.ccGroupMemberUnBanned",
      "payload": "Action, User, User, Group",
      "description": "A group member was unbanned"
    },
    {
      "name": "CometChatGroupEvents.ccOwnershipChanged",
      "payload": "Group, GroupMember",
      "description": "Group ownership was transferred"
    }
  ],
  "sdkListeners": [
    "onGroupMemberJoined",
    "onGroupMemberLeft",
    "onGroupMemberKicked",
    "onGroupMemberBanned",
    "onGroupMemberScopeChanged",
    "onMemberAddedToGroup",
    "onUserOnline",
    "onUserOffline"
  ]
}

Where It Fits

CometChatGroupMembers is a list component. It renders all members of a specific group and emits the selected GroupMember via setOnItemClick. It requires a Group object set via setGroup() before it can load data. Wire it to CometChatMessageHeader, CometChatMessageList, and CometChatMessageComposer to build a group messaging layout.
GroupChatActivity.kt
class GroupChatActivity : AppCompatActivity() {

    private lateinit var groupMembers: CometChatGroupMembers
    private lateinit var messageHeader: CometChatMessageHeader
    private lateinit var messageList: CometChatMessageList
    private lateinit var messageComposer: CometChatMessageComposer

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

        groupMembers = findViewById(R.id.group_members)
        messageHeader = findViewById(R.id.message_header)
        messageList = findViewById(R.id.message_list)
        messageComposer = findViewById(R.id.message_composer)

        val group = Group().apply {
            guid = "GROUP_ID"
            name = "GROUP_NAME"
        }
        groupMembers.setGroup(group)

        groupMembers.setOnItemClick { view, position, groupMember ->
            messageHeader.setUser(groupMember)
            messageList.setUser(groupMember)
            messageComposer.setUser(groupMember)
        }
    }
}

Quick Start

Add the component to your layout XML:
layout_activity.xml
<com.cometchat.chatuikit.groupmembers.CometChatGroupMembers
    android:id="@+id/group_member"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Prerequisites: CometChat SDK initialized with CometChatUIKit.init(), a user logged in, the cometchat-chat-uikit-android dependency added, and a valid Group object with a group ID (GUID). Set the Group object in your Activity or Fragment:
YourActivity.kt
val cometchatGroupMembers: CometChatGroupMembers = binding.groupMember

val group = Group().apply {
    guid = "GROUP_ID"
    name = "GROUP_NAME"
}

cometchatGroupMembers.setGroup(group)
What this does: Creates a Group object with a group ID and name, then passes it to the CometChatGroupMembers component. The component fetches and displays all members of that group.
Or add programmatically in an Activity:
YourActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val groupMembers = CometChatGroupMembers(this)
    val group = Group().apply {
        guid = "GROUP_ID"
        name = "GROUP_NAME"
    }
    groupMembers.setGroup(group)
    setContentView(groupMembers)
}
Or in a Fragment:
YourFragment.kt
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
    val groupMembers = CometChatGroupMembers(requireContext())
    val group = Group().apply {
        guid = "GROUP_ID"
        name = "GROUP_NAME"
    }
    groupMembers.setGroup(group)
    return groupMembers
}

Filtering Group Members

Pass a GroupMembersRequest.GroupMembersRequestBuilder to setGroupMembersRequestBuilder. Pass the builder instance — not the result of .build().
val builder = GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
    .setLimit(10)
cometchatGroupMembers.setGroupMembersRequestBuilder(builder)

Filter Recipes

RecipeCode
Limit to 10 per pagebuilder.setLimit(10)
Search by keywordbuilder.setSearchKeyword("john")
Filter by scopesbuilder.setScopes(Arrays.asList("admin", "moderator"))
Admins onlybuilder.setScopes(Arrays.asList("admin"))
Moderators onlybuilder.setScopes(Arrays.asList("moderator"))
Participants onlybuilder.setScopes(Arrays.asList("participant"))
The component uses infinite scroll — the next page loads as the user scrolls to the bottom.

Search Request Builder

Use setSearchRequestBuilder to customize the search list separately from the main list:
val searchBuilder = GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
    .setLimit(LIMIT)
    .setSearchKeyword(SEARCH_KEYWORD)
cometchatGroupMembers.setSearchRequestBuilder(searchBuilder)
What this does: Creates a GroupMembersRequestBuilder with a group ID, limit, and search keyword, then applies it as the search request builder. When the user searches, the component uses this builder to filter results.

Actions and Events

Callback Methods

setOnItemClick

Fires when a group member row is tapped. Primary navigation hook — set the active member and render the message view.
YourActivity.kt
cometchatGroupMembers.setOnItemClick { view, position, groupMember ->

}
What this does: Replaces the default item-click behavior. When a user taps a group member, your custom lambda executes instead of the built-in navigation.

setOnItemLongClick

Fires when a group member row is long-pressed. Use for additional actions like kick, ban, or change scope.
YourActivity.kt
cometchatGroupMembers.setOnItemLongClick { view, position, groupMember ->

}

setOnBackPressListener

Fires when the user presses the back button in the app bar. Default: navigates to the previous activity.
YourActivity.kt
cometchatGroupMembers.setOnBackPressListener {

}

setOnSelection

Fires when a group member is checked/unchecked in multi-select mode. Requires setSelectionMode to be set.
YourActivity.kt
cometchatGroupMembers.setOnSelection(object : OnSelection<GroupMember?> {
    override fun onSelection(t: MutableList<GroupMember?>?) {

    }
})

setOnError

Fires on internal errors (network failure, auth issue, SDK exception).
YourActivity.kt
cometchatGroupMembers.setOnError {

}

setOnLoadMore

Fires when the list is successfully fetched and loaded.
YourActivity.kt
cometchatGroupMembers.setOnLoadMore(object : OnLoad<GroupMember?> {
    override fun onLoad(list: MutableList<GroupMember?>?) {

    }
})

setOnEmpty

Fires when the list is empty, enabling custom handling such as showing a placeholder.
YourActivity.kt
cometchatGroupMembers.setOnEmpty {

}
  • Verify: After setting an action callback, trigger the corresponding user interaction (tap, long-press, back, select) and confirm your custom logic executes instead of the default behavior.

Global UI Events

CometChatGroupEvents emits events subscribable from anywhere in the application. Add a listener and remove it when no longer needed.
EventFires whenPayload
ccGroupMemberBannedA group member is banned from the groupAction, User, User, Group
ccGroupMemberKickedA group member is kicked from the groupAction, User, User, Group
ccGroupMemberScopeChangedA group member’s scope is changedAction, User, String, String, Group
ccGroupMemberAddedMembers are added to the groupList<Action>, List<User>, Group, User
ccGroupMemberUnBannedA group member is unbannedAction, User, User, Group
ccOwnershipChangedGroup ownership is transferredGroup, GroupMember
Add Listener
CometChatGroupEvents.addGroupListener("LISTENER_TAG", object : CometChatGroupEvents() {
    override fun ccGroupMemberKicked(
        actionMessage: Action,
        kickedUser: User,
        kickedBy: User,
        kickedFrom: Group
    ) {
        super.ccGroupMemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom)
    }

    override fun ccGroupMemberBanned(
        actionMessage: Action,
        bannedUser: User,
        bannedBy: User,
        bannedFrom: Group
    ) {
        super.ccGroupMemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom)
    }

    override fun ccGroupMemberScopeChanged(
        actionMessage: Action,
        updatedUser: User,
        scopeChangedTo: String,
        scopeChangedFrom: String,
        group: Group
    ) {
        super.ccGroupMemberScopeChanged(
            actionMessage,
            updatedUser,
            scopeChangedTo,
            scopeChangedFrom,
            group
        )
    }
})
Remove Listener
CometChatGroupEvents.removeListener("LISTENER_TAG")
What this does: Registers a global event listener tagged with "LISTENER_TAG". When a group member is kicked, banned, or has their scope changed, the corresponding callback fires with the action details, affected user, and group information.

SDK Events (Real-Time, Automatic)

The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.
SDK ListenerInternal behavior
onGroupMemberJoinedAdds the new member to the list
onGroupMemberLeftRemoves the member from the list
onGroupMemberKickedRemoves the kicked member from the list
onGroupMemberBannedRemoves the banned member from the list
onGroupMemberScopeChangedUpdates the member’s scope in the list
onMemberAddedToGroupAdds the new member to the list
onUserOnlineUpdates online status indicator for the member
onUserOfflineUpdates offline status indicator for the member
Automatic: group membership changes and user presence changes update the list in real time.

Functionality

Small functional customizations such as toggling visibility of UI elements and configuring selection modes.
MethodsDescriptionCode
setGroupSets the group whose members need to be fetched. Required for the component to function..setGroup(group);
setBackIconVisibilityToggles visibility for the back button in the app bar.setBackIconVisibility(View.VISIBLE);
setToolbarVisibilityToggles visibility for the toolbar in the app bar.setToolbarVisibility(View.GONE);
setLoadingStateVisibilityHides the loading state while fetching members.setLoadingStateVisibility(View.GONE);
setErrorStateVisibilityHides the error state on fetching members.setErrorStateVisibility(View.GONE);
setEmptyStateVisibilityHides the empty state on fetching members.setEmptyStateVisibility(View.GONE);
setSeparatorVisibilityControls visibility of separators in the list view.setSeparatorVisibility(View.GONE);
setUserStatusVisibilityControls visibility of the online status indicator.setUserStatusVisibility(View.GONE);
setSearchBoxVisibilityControls visibility of the search box in the toolbar.setSearchBoxVisibility(View.GONE);
setSelectionModeDetermines the selection mode (single or multiple).setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);
setSearchKeywordProgrammatically triggers a search with the given keyword.setSearchKeyword("anything");
setTitleTextSets a custom title in the toolbar.setTitleText("Members");
setKickMemberOptionVisibilityToggles visibility for the kick member option in the long-press menu.setKickMemberOptionVisibility(View.GONE);
setBanMemberOptionVisibilityToggles visibility for the ban member option in the long-press menu.setBanMemberOptionVisibility(View.GONE);
setScopeChangeOptionVisibilityToggles visibility for the scope change option in the long-press menu.setScopeChangeOptionVisibility(View.GONE);
excludeOwnerWhen true, excludes the group owner from the member list.excludeOwner(true);
  • Verify: After calling a visibility method, confirm the corresponding UI element is shown or hidden.

Custom View Slots

Each slot replaces a section of the default UI. Slots that accept a GroupMember parameter receive the group member object for that row via the GroupMembersViewHolderListeners pattern (createView + bindView).
SlotMethodReplaces
Leading viewsetLeadingView(GroupMembersViewHolderListeners)Avatar / left section
Title viewsetTitleView(GroupMembersViewHolderListeners)Name / title text
Subtitle viewsetSubtitleView(GroupMembersViewHolderListeners)Subtitle text below name
Trailing viewsetTrailingView(GroupMembersViewHolderListeners)Right section
Item viewsetItemView(GroupMembersViewHolderListeners)Entire list item row
Loading viewsetLoadingStateView(@LayoutRes int)Loading spinner
Empty viewsetEmptyStateView(@LayoutRes int)Empty state
Error viewsetErrorStateView(@LayoutRes int)Error state
Overflow menusetOverflowMenu(View)Toolbar menu
Options (replace)setOptions(Function3)Long-press context menu (replaces defaults)
Options (append)addOptions(Function3)Long-press context menu (appends to defaults)

setLeadingView

Replace the avatar / left section.
cometchatGroupMembers.setLeadingView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View? {
        return null
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
    }
})
What this does: Registers a GroupMembersViewHolderListeners that provides a custom view for the leading (left) area of each group member item. createView inflates your layout, and bindView populates it with group member data.
Scope badge avatar example:
Create a custom layout file named custom_title_view.xml:
custom_title_view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="@dimen/cometchat_45dp"
    android:layout_height="@dimen/cometchat_45dp"
    android:orientation="vertical">

    <com.cometchat.chatuikit.shared.views.avatar.CometChatAvatar
        android:id="@+id/avatar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <View
        android:id="@+id/batch_view"
        android:layout_width="match_parent"
        android:layout_height="@dimen/cometchat_12dp"
        android:layout_alignParentBottom="true"
        android:background="@drawable/admin_batch"
        android:visibility="gone" />

</RelativeLayout>
What this does: Defines a custom leading view layout with a CometChatAvatar and a role badge view that can display different backgrounds based on the member’s scope (admin, moderator, participant).
YourActivity.kt
cometchatGroupMembers.setLeadingView(object : GroupMembersViewHolderListeners() {
    override fun createView(context: Context?, listItem: CometchatGroupMemberListItemBinding?): View {
        return LayoutInflater.from(context).inflate(R.layout.header_leading_view, null, false)
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
        val avatar = createdView.findViewById<CometChatAvatar>(R.id.avatar)
        avatar.setAvatar(groupMember.name, groupMember.avatar)
        val role = createdView.findViewById<View>(R.id.batch_view)
        if (UIKitConstants.GroupMemberScope.ADMIN == groupMember.scope) {
            role.visibility = View.VISIBLE
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.marketing_head, null)
        } else if (UIKitConstants.GroupMemberScope.MODERATOR == groupMember.scope) {
            role.visibility = View.VISIBLE
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.sr_manager, null)
        } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS == groupMember.scope) {
            role.visibility = View.VISIBLE
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.content_manager, null)
        } else {
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.team_member, null)
        }
        val layoutParams = LinearLayout.LayoutParams(
            Utils.convertDpToPx(context, 40),
            Utils.convertDpToPx(context, 40)
        )
        createdView.layoutParams = layoutParams
    }
})
What this does: Inflates a custom leading view layout and populates it with the group member’s avatar and a role-based badge. If the member is an admin, the badge shows the marketing_head drawable; if a moderator, sr_manager; if a participant, content_manager; otherwise, team_member. The view is sized to 40dp × 40dp.

setTitleView

Replace the name / title text.
cometchatGroupMembers.setTitleView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View? {
        return null
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
    }
})
Inline role badge example:
Create a custom layout file named custom_title_view.xml:
custom_title_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/user_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="teacher"
        android:textAppearance="?attr/cometchatTextAppearanceHeading4Medium"
        android:textColor="?attr/cometchatTextColorPrimary" />

    <View
        android:id="@+id/role"
        android:layout_width="50dp"
        android:layout_height="15dp"
        android:layout_marginStart="@dimen/cometchat_16dp"
        android:background="@drawable/team_member" />
</LinearLayout>
What this does: Defines a custom title view layout with a TextView for the member name and a View for the role badge, arranged horizontally.
YourActivity.kt
cometchatGroupMembers.setTitleView(object : GroupMembersViewHolderListeners() {
    override fun createView(context: Context?, listItem: CometchatGroupMemberListItemBinding?): View {
        return LayoutInflater.from(context).inflate(R.layout.custom_title_view, null, false)
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
        val layout = createdView.findViewById<LinearLayout>(R.id.user_layout)
        val layoutParams = LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
        layout.layoutParams = layoutParams
        val name = createdView.findViewById<TextView>(R.id.title)
        name.text = groupMember.name
        val role = createdView.findViewById<View>(R.id.role)
        if (UIKitConstants.GroupMemberScope.ADMIN == groupMember.scope) {
            role.visibility = View.VISIBLE
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.marketing_head, null)
        } else if (UIKitConstants.GroupMemberScope.MODERATOR == groupMember.scope) {
            role.visibility = View.VISIBLE
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.sr_manager, null)
        } else if (UIKitConstants.GroupMemberScope.PARTICIPANTS == groupMember.scope) {
            role.visibility = View.VISIBLE
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.content_manager, null)
        } else {
            role.background = ResourcesCompat.getDrawable(resources, R.drawable.team_member, null)
        }
    }
})
What this does: Inflates a custom title view layout and populates it with the group member’s name and a role-based badge. The badge background changes based on the member’s scope: marketing_head for admin, sr_manager for moderator, content_manager for participant, and team_member for others.

setSubtitleView

Replace the subtitle text below the member’s name.
cometchatGroupMembers.setSubtitleView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View? {
        return null
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
    }
})
Example with join date:
YourActivity.kt
cometchatGroupMembers.setSubtitleView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View {
        return TextView(context)
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
        (createdView as TextView).text =
            "Joined at: " + SimpleDateFormat("dd/MM/yyyy, HH:mm:ss").format(groupMember.joinedAt * 1000)
    }
})
What this does: Creates a TextView as the subtitle view and populates it with the group member’s join date formatted as “dd/MM/yyyy, HH:mm:ss”. The joinedAt timestamp is multiplied by 1000 to convert from seconds to milliseconds.

setTrailingView

Replace the right section of each group member item.
cometchatGroupMembers.setTrailingView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View? {
        return null
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
    }
})
Scope badge example:
Create a custom layout file named custom_tail_view.xml:
custom_tail_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/scope_card"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        app:cardBackgroundColor="?attr/cometchatPrimaryColor"
        app:cardCornerRadius="@dimen/cometchat_radius_max"
        app:cardElevation="@dimen/cometchat_0dp">

        <TextView
            android:id="@+id/tv_scope"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:paddingStart="@dimen/cometchat_padding_3"
            android:paddingTop="@dimen/cometchat_padding_1"
            android:paddingEnd="@dimen/cometchat_padding_3"
            android:paddingBottom="@dimen/cometchat_padding_1"
            android:text="@string/cometchat_owner"
            android:textAppearance="?attr/cometchatTextAppearanceCaption1Regular"
            android:textColor="?attr/cometchatPrimaryColor" />

    </com.google.android.material.card.MaterialCardView>

</LinearLayout>
What this does: Defines a custom trailing view layout with a MaterialCardView containing a TextView that displays the member’s scope as a colored badge.
YourActivity.kt
cometchatGroupMembers.setTrailingView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View {
        return View.inflate(context, R.layout.custom_tail_view, null)
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
        val cardView = createdView.findViewById<MaterialCardView>(R.id.scope_card)
        val tvName = createdView.findViewById<TextView>(R.id.tv_scope)
        cardView.setCardBackgroundColor(CometChatTheme.getExtendedPrimaryColor100(context))
        tvName.text = groupMember.scope
        createdView.visibility =
            if (groupMember.scope == UIKitConstants.GroupMemberScope.PARTICIPANTS) View.VISIBLE else View.GONE
    }
})
What this does: Inflates a custom trailing view that displays a scope badge for each group member. The badge background uses the extended primary color, the text shows the member’s scope, and the badge is only visible for participants (hidden for admins, moderators, and owners).

setItemView

Replace the entire list item row.
cometchatGroupMembers.setItemView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View? {
        return null
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
    }
})
Example with name and scope:
Create a custom layout file named item_list.xml:
item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:textAppearance="?attr/cometchatTextAppearanceHeading4Bold"
        android:textColor="?attr/cometchatTextColorPrimary" />

    <TextView
        android:id="@+id/tvSubtitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/cometchat_margin_1"
        android:textAppearance="?attr/cometchatTextAppearanceBodyRegular"
        android:textColor="?attr/cometchatTextColorSecondary" />
</LinearLayout>
What this does: Defines a custom list item layout with two TextView elements: one for the member name and one for the subtitle (scope), arranged vertically.
YourActivity.kt
cometchatGroupMembers.setItemView(object : GroupMembersViewHolderListeners() {
    override fun createView(
        context: Context?,
        listItem: CometchatGroupMemberListItemBinding?
    ): View {
        return View.inflate(context, R.layout.custom_group_list_item, null)
    }

    override fun bindView(
        context: Context,
        createdView: View,
        groupMember: GroupMember,
        group: Group,
        holder: RecyclerView.ViewHolder,
        groupMemberList: List<GroupMember>,
        position: Int
    ) {
        val tvName = createdView.findViewById<TextView>(R.id.tvName)
        val tvScope = createdView.findViewById<TextView>(R.id.tvSubtitle)
        tvName.text = groupMember.name
        tvScope.text = groupMember.scope
    }
})
What this does: Inflates a custom list item layout and populates it with the group member’s name and scope. Each list item shows the member name in the primary text style and their scope (admin, moderator, participant) in the secondary text style.

setOptions

Replace the long-press context menu entirely.
cometchatGroupMembers.setOptions { context, groupMember, group -> emptyList<CometChatPopupMenu.MenuItem?>() }

addOptions

Append to the long-press context menu without removing defaults.
cometchatGroupMembers.addOptions { context, groupMember, group -> emptyList<CometChatPopupMenu.MenuItem?>() }

setLoadingStateView

Sets a custom loading view displayed when data is being fetched.
cometchatGroupMembers.setLoadingStateView(R.layout.your_loading_view)

setEmptyStateView

Configures a custom view displayed when there are no group members in the list.
cometchatGroupMembers.setEmptyStateView(R.layout.your_empty_view)

setErrorStateView

Defines a custom error state view that appears when an issue occurs while loading group members.
cometchatGroupMembers.setErrorStateView(R.layout.your_error_view)

setOverflowMenu

Replace the toolbar overflow menu.
val addMemberIv = ImageView(this)
addMemberIv.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_add, null))
cometchatGroupMembers.setOverflowMenu(addMemberIv)
What this does: Creates an ImageView with an add icon and sets it as the overflow menu in the group members toolbar. This provides a quick action button for adding new members.
  • Verify: After setting any custom view slot, confirm the custom view renders in the correct position within the group member list item, and the data binding populates correctly for each member.

Common Patterns

Hide all chrome — minimal list

cometchatGroupMembers.setUserStatusVisibility(View.GONE)
cometchatGroupMembers.setSeparatorVisibility(View.GONE)
cometchatGroupMembers.setToolbarVisibility(View.GONE)

Admins-only list

val builder = GroupMembersRequest.GroupMembersRequestBuilder("GROUP_ID")
    .setScopes(listOf("admin"))
cometchatGroupMembers.setGroupMembersRequestBuilder(builder)

Exclude group owner

cometchatGroupMembers.excludeOwner(true)

Hide kick/ban/scope options

cometchatGroupMembers.setKickMemberOptionVisibility(View.GONE)
cometchatGroupMembers.setBanMemberOptionVisibility(View.GONE)
cometchatGroupMembers.setScopeChangeOptionVisibility(View.GONE)

Advanced Methods

Programmatic Selection

selectGroupMember

Programmatically selects or deselects a group member. Works with both SINGLE and MULTIPLE selection modes.
// Select a member in single-select mode
cometchatGroupMembers.selectGroupMember(groupMember, UIKitConstants.SelectionMode.SINGLE)

// Select a member in multi-select mode
cometchatGroupMembers.selectGroupMember(groupMember, UIKitConstants.SelectionMode.MULTIPLE)
In SINGLE mode, selecting a new member replaces the previous selection. In MULTIPLE mode, calling this on an already-selected member deselects it (toggle behavior).

getSelectedGroupMembers

Returns the list of currently selected GroupMember objects.
val selected = cometchatGroupMembers.selectedGroupMembers

Selected Group Members List

When using multi-select mode, a horizontal list of selected group members can be shown above the main list.
MethodTypeDescription
setSelectedGroupMembersListVisibilityint (View.VISIBLE / View.GONE)Show or hide the selected members strip
setSelectedGroupMemberAvatarStyle@StyleRes intAvatar style for selected member chips
setSelectedGroupMemberItemTextColor@ColorInt intText color for selected member names
setSelectedGroupMemberItemTextAppearance@StyleRes intText appearance for selected member names
setSelectedGroupMemberItemRemoveIconDrawableIcon for the remove button on each chip
setSelectedGroupMemberItemRemoveIconTint@ColorInt intTint color for the remove icon

Search Input Customization

The built-in search box can be customized programmatically:
MethodTypeDescription
setSearchInputTextColor@ColorInt intText color of the search input
setSearchInputPlaceHolderTextColor@ColorInt intPlaceholder text color
setSearchInputIconDrawableLeading icon in the search box
setSearchInputIconTint@ColorInt intTint for the leading icon
setSearchInputEndIconDrawableTrailing icon in the search box
setSearchInputEndIconTint@ColorInt intTint for the trailing icon
setSearchInputStrokeWidth@Dimension intStroke width of the search box border
setSearchInputStrokeColor@ColorInt intStroke color of the search box border
setSearchInputBackgroundColor@ColorInt intBackground color of the search box
setSearchInputCornerRadius@Dimension intCorner radius of the search box
setSearchInputTextAppearance@StyleRes intText appearance of the search input

Internal Access

These methods provide direct access to internal components for advanced use cases.
MethodReturnsDescription
getBinding()CometchatGroupMembersListViewBindingThe ViewBinding for the component’s root layout
getViewModel()GroupMembersViewModelThe ViewModel managing group member data and state
getAdapter()GroupMembersAdapterThe adapter powering the RecyclerView
setAdapter(GroupMembersAdapter)voidReplaces the default adapter with a custom one
getRecyclerView()RecyclerViewThe RecyclerView displaying the member list
Use these only when the standard API is insufficient. Directly manipulating the adapter or ViewModel may conflict with the component’s internal state management.

Style

The component uses XML theme styles. Define a custom style with parent CometChatGroupMembersStyle in themes.xml, then apply with setStyle().
themes.xml
    <style name="CustomAvatarStyle" parent="CometChatAvatarStyle">
        <item name="cometchatAvatarStrokeRadius">8dp</item>
        <item name="cometchatAvatarBackgroundColor">#FBAA75</item>
    </style>

    <style name="CustomGroupMembersStyle" parent="CometChatGroupMembersStyle">
        <item name="cometchatGroupMembersAvatarStyle">@style/CustomAvatarStyle</item>
        <item name="cometchatGroupMembersSeparatorColor">#F76808</item>
        <item name="cometchatGroupMembersTitleTextColor">#F76808</item>
        <item name="cometchatGroupMembersBackIconTint">#F76808</item>
    </style>
cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle)
What this does: Applies the CustomGroupMembersStyle theme to the CometChatGroupMembers component, changing the avatar, separator, title text, and back icon appearance.
To know more such attributes, visit the attributes file.

Programmatic Style Properties

In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:
MethodTypeDescription
setBackgroundColor@ColorInt intBackground color of the component
setBackIconTint@ColorInt intTint color for the back icon
setBackIconDrawableCustom back icon drawable
setTitleTextColor@ColorInt intTitle text color in the toolbar
setTitleTextAppearance@StyleRes intTitle text appearance in the toolbar
setItemTitleTextColor@ColorInt intText color for member item titles
setItemTitleTextAppearance@StyleRes intText appearance for member item titles
setSeparatorColor@ColorInt intColor of list item separators
setSeparatorHeight@Dimension intHeight of list item separators
setCornerRadius@Dimension intCorner radius of the component
setEmptyStateTitleTextColor@ColorInt intTitle text color for the empty state
setEmptyStateTitleTextAppearance@StyleRes intTitle text appearance for the empty state
setEmptyStateSubtitleTextColor@ColorInt intSubtitle text color for the empty state
setEmptyStateSubtitleTextAppearance@StyleRes intSubtitle text appearance for the empty state
setErrorStateTitleTextColor@ColorInt intTitle text color for the error state
setErrorStateTitleTextAppearance@StyleRes intTitle text appearance for the error state
setErrorStateSubtitleTextColor@ColorInt intSubtitle text color for the error state
setErrorStateSubtitleTextAppearance@StyleRes intSubtitle text appearance for the error state
setAvatarStyle@StyleRes intStyle for member avatars
setStatusIndicatorStyle@StyleRes intStyle for online/offline status indicators

Checkbox Style Properties (Selection Mode)

When using SINGLE or MULTIPLE selection mode, checkboxes appear on each item:
MethodTypeDescription
setCheckBoxStrokeWidth@Dimension intStroke width of the checkbox border
setCheckBoxCornerRadius@Dimension intCorner radius of the checkbox
setCheckBoxStrokeColor@ColorInt intStroke color of the checkbox border
setCheckBoxBackgroundColor@ColorInt intBackground color of unchecked checkbox
setCheckBoxCheckedBackgroundColor@ColorInt intBackground color of checked checkbox
setSelectIconDrawableIcon shown when checkbox is checked
setSelectIconTint@ColorInt intTint for the checkbox select icon
setDiscardSelectionIconDrawableIcon for the discard selection button
setDiscardSelectionIconTint@ColorInt intTint for the discard selection icon
setSubmitSelectionIconDrawableIcon for the submit selection button
setSubmitSelectionIconTint@ColorInt intTint for the submit selection icon

Customization Matrix

What to changeWhereProperty/APIExample
Override behavior on member interactionActivity/FragmentsetOn<Event> callbackssetOnItemClick((v, pos, m) -> { ... })
Filter which members appearActivity/FragmentsetGroupMembersRequestBuildersetGroupMembersRequestBuilder(builder)
Customize search resultsActivity/FragmentsetSearchRequestBuildersetSearchRequestBuilder(builder)
Toggle visibility of UI elementsActivity/Fragmentset<Feature>Visibility(int)setUserStatusVisibility(View.GONE)
Replace a section of the list itemActivity/Fragmentset<Slot>ViewsetLeadingView(listener)
Change colors, fonts, spacingthemes.xmlCometChatGroupMembersStyle<item name="cometchatGroupMembersSeparatorColor">#F76808</item>
Avatar style (corner radius, background)themes.xmlcometchatGroupMembersAvatarStyle<item name="cometchatAvatarStrokeRadius">8dp</item>
Apply a custom styleActivity/FragmentsetStyle(int styleRes)cometchatGroupMembers.setStyle(R.style.CustomGroupMembersStyle);
Set the groupActivity/FragmentsetGroup(Group).setGroup(group);
Back button visibilityActivity/FragmentsetBackIconVisibility(int).setBackIconVisibility(View.VISIBLE);
Toolbar visibilityActivity/FragmentsetToolbarVisibility(int).setToolbarVisibility(View.GONE);
Error state visibilityActivity/FragmentsetErrorStateVisibility(int).setErrorStateVisibility(View.GONE);
Empty state visibilityActivity/FragmentsetEmptyStateVisibility(int).setEmptyStateVisibility(View.GONE);
Loading state visibilityActivity/FragmentsetLoadingStateVisibility(int).setLoadingStateVisibility(View.GONE);
Separator visibilityActivity/FragmentsetSeparatorVisibility(int).setSeparatorVisibility(View.GONE);
User online status visibilityActivity/FragmentsetUserStatusVisibility(int).setUserStatusVisibility(View.GONE);
Selection mode (single/multiple)Activity/FragmentsetSelectionMode(SelectionMode).setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);
Search keywordActivity/FragmentsetSearchKeyword(String).setSearchKeyword("anything");
Search box visibilityActivity/FragmentsetSearchBoxVisibility(int).setSearchBoxVisibility(View.GONE);
Custom toolbar titleActivity/FragmentsetTitleText(String).setTitleText("Members");
Long-press options (replace)Activity/FragmentsetOptions(Function3)See setOptions code above
Long-press options (append)Activity/FragmentaddOptions(Function3)See addOptions code above
Loading viewActivity/FragmentsetLoadingStateView(int).setLoadingStateView(R.layout.your_loading_view);
Empty viewActivity/FragmentsetEmptyStateView(int).setEmptyStateView(R.layout.your_empty_view);
Error viewActivity/FragmentsetErrorStateView(int).setErrorStateView(R.layout.your_error_view);
Leading view (avatar area)Activity/FragmentsetLeadingView(GroupMembersViewHolderListeners)See setLeadingView code above
Title viewActivity/FragmentsetTitleView(GroupMembersViewHolderListeners)See setTitleView code above
Subtitle viewActivity/FragmentsetSubtitleView(GroupMembersViewHolderListeners)See setSubtitleView code above
Trailing viewActivity/FragmentsetTrailingView(GroupMembersViewHolderListeners)See setTrailingView code above
Entire list itemActivity/FragmentsetItemView(GroupMembersViewHolderListeners)See setItemView code above
Overflow menuActivity/FragmentsetOverflowMenu(View)cometchatGroupMembers.setOverflowMenu(view);
Kick member option visibilityActivity/FragmentsetKickMemberOptionVisibility(int).setKickMemberOptionVisibility(View.GONE);
Ban member option visibilityActivity/FragmentsetBanMemberOptionVisibility(int).setBanMemberOptionVisibility(View.GONE);
Scope change option visibilityActivity/FragmentsetScopeChangeOptionVisibility(int).setScopeChangeOptionVisibility(View.GONE);
Exclude group ownerActivity/FragmentexcludeOwner(boolean).excludeOwner(true);
Programmatic selectionActivity/FragmentselectGroupMember(GroupMember, SelectionMode).selectGroupMember(member, SelectionMode.SINGLE);
Selected members stripActivity/FragmentsetSelectedGroupMembersListVisibility(int).setSelectedGroupMembersListVisibility(View.VISIBLE);
Internal adapter accessActivity/FragmentgetAdapter() / setAdapter()Advanced use only

Accessibility

The component renders a scrollable RecyclerView of interactive group member items. Each member row responds to tap and long-press gestures. Avatar images include the member name as content description. For custom views provided via setLeadingView, setTitleView, setTrailingView, or setItemView, ensure you set android:contentDescription on visual-only elements so TalkBack can announce them. The default views handle this automatically. Online/offline status dots are visual-only by default. If screen reader descriptions are needed, provide them via a custom view with appropriate contentDescription attributes. Scope badges (admin, moderator, participant) should also include content descriptions when using custom trailing views.

Next Steps