> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-rn-guide-message-privately.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Groups

> Display CometChat Android UI Kit groups with avatars, member counts, group type indicators, search, filtering, join, and conversation actions.

<Accordion title="AI Integration Quick Reference">
  ```json theme={null}
  {
    "component": "CometChatGroups",
    "package": "com.cometchat.chatuikit.groups",
    "xmlElement": "<com.cometchat.chatuikit.groups.CometChatGroups />",
    "description": "Scrollable list of all available groups with search, avatars, names, and group type indicators (public, private, password-protected).",
    "primaryOutput": {
      "method": "setOnItemClick",
      "type": "OnItemClick<Group>"
    },
    "methods": {
      "data": {
        "setGroupsRequestBuilder": {
          "type": "GroupsRequest.GroupsRequestBuilder",
          "default": "SDK default",
          "note": "Pass the builder, not the result of .build()"
        },
        "setSearchRequestBuilder": {
          "type": "GroupsRequest.GroupsRequestBuilder",
          "default": "Same as main builder",
          "note": "Separate builder for search results"
        }
      },
      "callbacks": {
        "setOnItemClick": "OnItemClick<Group>",
        "setOnItemLongClick": "OnItemLongClick<Group>",
        "setOnBackPressListener": "OnBackPress",
        "setOnSelection": "OnSelection<Group>",
        "setOnError": "OnError",
        "setOnLoad": "OnLoad<Group>",
        "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" },
        "setGroupTypeVisibility": { "type": "int", "default": "View.VISIBLE" },
        "setSearchBoxVisibility": { "type": "int", "default": "View.VISIBLE" }
      },
      "selection": {
        "setSelectionMode": {
          "type": "UIKitConstants.SelectionMode",
          "values": ["NONE", "SINGLE", "MULTIPLE"],
          "default": "NONE"
        }
      },
      "viewSlots": {
        "setItemView": "GroupsViewHolderListener — entire list item row",
        "setLeadingView": "GroupsViewHolderListener — avatar / left section",
        "setTitleView": "GroupsViewHolderListener — name / title text",
        "setSubtitleView": "GroupsViewHolderListener — subtitle text below name",
        "setTrailingView": "GroupsViewHolderListener — right section",
        "setLoadingView": "@LayoutRes int — loading spinner",
        "setEmptyView": "@LayoutRes int — empty state",
        "setErrorView": "@LayoutRes int — error state",
        "setOverflowMenu": "View — toolbar menu",
        "setOptions": "Function2<Context, Group, List<MenuItem>> — long-press context menu (replaces defaults)",
        "addOptions": "Function2<Context, Group, List<MenuItem>> — long-press context menu (appends to defaults)"
      },
      "advanced": {
        "selectGroup": "Group, SelectionMode — programmatic selection",
        "clearSelection": "void — clears all selected groups",
        "getSelectedGroups": "List<Group> — returns selected items",
        "setSearchKeyword": "String — programmatic search",
        "setTitleText": "String — custom toolbar title",
        "setSearchPlaceholderText": "String — search placeholder",
        "getBinding": "CometchatGroupListBinding — root ViewBinding",
        "getViewModel": "GroupsViewModel — internal ViewModel access",
        "getAdapter": "GroupsAdapter — internal adapter access",
        "setAdapter": "GroupsAdapter — replace the default adapter"
      },
      "style": {
        "setStyle": {
          "type": "@StyleRes int",
          "parent": "CometChatGroupsStyle"
        }
      }
    },
    "events": [
      {
        "name": "CometChatGroupEvents.ccGroupCreated",
        "payload": "Group",
        "description": "Logged-in user created a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupDeleted",
        "payload": "Group",
        "description": "Logged-in user deleted a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupLeft",
        "payload": "Action, User, Group",
        "description": "Logged-in user left a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupMemberJoined",
        "payload": "User, Group",
        "description": "Logged-in user joined a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupMemberAdded",
        "payload": "List<Action>, List<User>, Group, User",
        "description": "Logged-in user added members to a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupMemberKicked",
        "payload": "Action, User, User, Group",
        "description": "Logged-in user kicked a member from a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupMemberBanned",
        "payload": "Action, User, User, Group",
        "description": "Logged-in user banned a member from a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupMemberUnBanned",
        "payload": "Action, User, User, Group",
        "description": "Logged-in user unbanned a member from a group"
      },
      {
        "name": "CometChatGroupEvents.ccGroupMemberScopeChanged",
        "payload": "Action, User, String, String, Group",
        "description": "Logged-in user changed a member's scope"
      },
      {
        "name": "CometChatGroupEvents.ccOwnershipChanged",
        "payload": "Group, GroupMember",
        "description": "Logged-in user transferred group ownership"
      }
    ],
    "sdkListeners": [
      "onGroupMemberJoined",
      "onGroupMemberLeft",
      "onGroupMemberKicked",
      "onGroupMemberBanned",
      "onGroupMemberUnbanned",
      "onGroupMemberScopeChanged",
      "onMemberAddedToGroup"
    ]
  }
  ```
</Accordion>

## Where It Fits

`CometChatGroups` is a list component. It renders all available groups and emits the selected `Group` via `setOnItemClick`. Wire it to `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to build a group messaging layout.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin ChatActivity.kt lines theme={null}
    class ChatActivity : AppCompatActivity() {

        private lateinit var groups: CometChatGroups
        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_chat)

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

            groups.setOnItemClick { view, position, group ->
                messageHeader.setGroup(group)
                messageList.setGroup(group)
                messageComposer.setGroup(group)
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java ChatActivity.java lines theme={null}
    public class ChatActivity extends AppCompatActivity {

        private CometChatGroups groups;
        private CometChatMessageHeader messageHeader;
        private CometChatMessageList messageList;
        private CometChatMessageComposer messageComposer;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_chat);

            groups = findViewById(R.id.groups);
            messageHeader = findViewById(R.id.message_header);
            messageList = findViewById(R.id.message_list);
            messageComposer = findViewById(R.id.message_composer);

            groups.setOnItemClick((view, position, group) -> {
                messageHeader.setGroup(group);
                messageList.setGroup(group);
                messageComposer.setGroup(group);
            });
        }
    }
    ```
  </Tab>
</Tabs>

## Quick Start

Add the component to your layout XML:

```xml layout_activity.xml lines theme={null}
<com.cometchat.chatuikit.groups.CometChatGroups
    android:id="@+id/groups"
    android:layout_height="match_parent"
    android:layout_width="match_parent" />
```

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/ubfBSdV1t6rmjxeA/images/8f0fe074-groups-876f11ccd26289efd7bd12d29a1bc205.png?fit=max&auto=format&n=ubfBSdV1t6rmjxeA&q=85&s=1b10ff54c2c34f69c7c2d96345435466" width="1280" height="800" data-path="images/8f0fe074-groups-876f11ccd26289efd7bd12d29a1bc205.png" />
</Frame>

Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the `cometchat-chat-uikit-android` dependency added.

To add programmatically in an Activity:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(CometChatGroups(this))
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new CometChatGroups(this));
    }
    ```
  </Tab>
</Tabs>

Or in a Fragment:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourFragment.kt lines theme={null}
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return CometChatGroups(requireContext())
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java YourFragment.java lines theme={null}
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return new CometChatGroups(getContext());
    }
    ```
  </Tab>
</Tabs>

## Filtering Groups

Pass a `GroupsRequest.GroupsRequestBuilder` to `setGroupsRequestBuilder`. Pass the builder instance — not the result of `.build()`.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    val builder = GroupsRequestBuilder()
        .setLimit(10)
        .joinedOnly(true)
    cometchatGroups.setGroupsRequestBuilder(builder)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder()
        .setLimit(10)
        .joinedOnly(true);
    cometchatGroups.setGroupsRequestBuilder(builder);
    ```
  </Tab>
</Tabs>

### Filter Recipes

| Recipe               | Code                                    |
| -------------------- | --------------------------------------- |
| Joined only          | `builder.joinedOnly(true)`              |
| Limit to 10 per page | `builder.setLimit(10)`                  |
| Search by keyword    | `builder.setSearchKeyWord("design")`    |
| Filter by tags       | `builder.setTags(Arrays.asList("vip"))` |
| With tags            | `builder.withTags(true)`                |

> The component uses infinite scroll — the next page loads as the user scrolls to the bottom. Refer to [GroupsRequestBuilder](/sdk/android/retrieve-groups) for the full builder API.

### Search Request Builder

Use `setSearchRequestBuilder` to customize the search list separately from the main list:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    val searchBuilder = GroupsRequestBuilder()
        .setLimit(10)
        .setSearchKeyWord("**")
    cometchatGroups.setSearchRequestBuilder(searchBuilder)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    GroupsRequest.GroupsRequestBuilder searchBuilder = new GroupsRequest.GroupsRequestBuilder()
        .setLimit(10)
        .setSearchKeyWord("**");
    cometchatGroups.setSearchRequestBuilder(searchBuilder);
    ```
  </Tab>
</Tabs>

## Actions and Events

### Callback Methods

#### `setOnItemClick`

Fires when a group row is tapped. Primary navigation hook — set the active group and render the message view.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.onItemClick = OnItemClick { view, position, group ->
                
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnItemClick((view1, position, group) -> {
                
    });
    ```
  </Tab>
</Tabs>

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

#### `setOnItemLongClick`

Fires when a group row is long-pressed. Use for additional actions like delete or leave.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.onItemLongClick = OnItemLongClick({ view, position, group ->
                
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnItemLongClick((view1, position, group) -> {

    });
    ```
  </Tab>
</Tabs>

#### `setOnBackPressListener`

Fires when the user presses the back button in the app bar. Default: navigates to the previous activity.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.onBackPressListener = OnBackPress {

    }
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnBackPressListener(() -> {
                
    });
    ```
  </Tab>
</Tabs>

#### `setOnSelection`

Fires when a group is checked/unchecked in multi-select mode. Requires `setSelectionMode` to be set.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.setOnSelection(object : OnSelection<Group?> {
        override fun onSelection(t: MutableList<Group?>?) {
                    
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnSelection(t -> {

    });
    ```
  </Tab>
</Tabs>

#### `setOnError`

Fires on internal errors (network failure, auth issue, SDK exception).

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.setOnError {

    }
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnError(cometchatException -> {

    });
    ```
  </Tab>
</Tabs>

#### `setOnLoad`

Fires when the list is successfully fetched and loaded.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.setOnLoad(object : OnLoad<Group?> {
        override fun onLoad(list: MutableList<Group?>?) {

        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnLoad(list -> {

    });
    ```
  </Tab>
</Tabs>

#### `setOnEmpty`

Fires when the list is empty, enabling custom handling such as showing a placeholder.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.setOnEmpty {
                
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setOnEmpty(() -> {
                
    });
    ```
  </Tab>
</Tabs>

* **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.

| Event                       | Fires when                                   | Payload                                 |
| --------------------------- | -------------------------------------------- | --------------------------------------- |
| `ccGroupCreated`            | The logged-in user creates a group           | `Group`                                 |
| `ccGroupDeleted`            | The logged-in user deletes a group           | `Group`                                 |
| `ccGroupLeft`               | The logged-in user leaves a group            | `Action, User, Group`                   |
| `ccGroupMemberJoined`       | The logged-in user joins a group             | `User, Group`                           |
| `ccGroupMemberAdded`        | The logged-in user adds members to a group   | `List<Action>, List<User>, Group, User` |
| `ccGroupMemberKicked`       | The logged-in user kicks a member            | `Action, User, User, Group`             |
| `ccGroupMemberBanned`       | The logged-in user bans a member             | `Action, User, User, Group`             |
| `ccGroupMemberUnBanned`     | The logged-in user unbans a member           | `Action, User, User, Group`             |
| `ccGroupMemberScopeChanged` | The logged-in user changes a member's scope  | `Action, User, String, String, Group`   |
| `ccOwnershipChanged`        | The logged-in user transfers group ownership | `Group, GroupMember`                    |

<Tabs>
  <Tab title="Kotlin">
    ```kotlin Add Listener lines theme={null}
    CometChatGroupEvents.addGroupListener("LISTENER_TAG", object : CometChatGroupEvents() {
        override fun ccGroupCreated(group: Group?) {
            super.ccGroupCreated(group)
        }

        override fun ccGroupDeleted(group: Group?) {
            super.ccGroupDeleted(group)
        }

        override fun ccGroupLeft(actionMessage: Action?, leftUser: User?, leftGroup: Group?) {
            super.ccGroupLeft(actionMessage, leftUser, leftGroup)
        }

        override fun ccGroupMemberJoined(joinedUser: User?, joinedGroup: Group?) {
            super.ccGroupMemberJoined(joinedUser, joinedGroup)
        }

        override fun ccGroupMemberAdded(
            actionMessages: List<Action?>?,
            usersAdded: List<User?>?,
            userAddedIn: Group?,
            addedBy: User?
        ) {
            super.ccGroupMemberAdded(actionMessages, usersAdded, userAddedIn, addedBy)
        }

        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 ccGroupMemberUnBanned(
            actionMessage: Action?,
            unbannedUser: User?,
            unBannedBy: User?,
            unBannedFrom: Group?
        ) {
            super.ccGroupMemberUnBanned(actionMessage, unbannedUser, unBannedBy, unBannedFrom)
        }

        override fun ccGroupMemberScopeChanged(
            actionMessage: Action?,
            updatedUser: User?,
            scopeChangedTo: String?,
            scopeChangedFrom: String?,
            group: Group?
        ) {
            super.ccGroupMemberScopeChanged(
                actionMessage,
                updatedUser,
                scopeChangedTo,
                scopeChangedFrom,
                group
            )
        }

        override fun ccOwnershipChanged(group: Group?, newOwner: GroupMember?) {
            super.ccOwnershipChanged(group, newOwner)
        }
    })
    ```

    Remove Listener

    ```
    CometChatGroupEvents.removeListeners()
    ```
  </Tab>

  <Tab title="Java">
    ```java Add Listener lines theme={null}
    CometChatGroupEvents.addGroupListener("LISTENER_TAG", new CometChatGroupEvents() {
        @Override
        public void ccGroupCreated(Group group) {
            super.ccGroupCreated(group);
        }

        @Override
        public void ccGroupDeleted(Group group) {
            super.ccGroupDeleted(group);
        }

        @Override
        public void ccGroupLeft(Action actionMessage, User leftUser, Group leftGroup) {
            super.ccGroupLeft(actionMessage, leftUser, leftGroup);
        }

        @Override
        public void ccGroupMemberJoined(User joinedUser, Group joinedGroup) {
            super.ccGroupMemberJoined(joinedUser, joinedGroup);
        }

        @Override
        public void ccGroupMemberAdded(List<Action> actionMessages, List<User> usersAdded, Group userAddedIn, User addedBy) {
            super.ccGroupMemberAdded(actionMessages, usersAdded, userAddedIn, addedBy);
        }

        @Override
        public void ccGroupMemberKicked(Action actionMessage, User kickedUser, User kickedBy, Group kickedFrom) {
            super.ccGroupMemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom);
        }

        @Override
        public void ccGroupMemberBanned(Action actionMessage, User bannedUser, User bannedBy, Group bannedFrom) {
            super.ccGroupMemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom);
        }

        @Override
        public void ccGroupMemberUnBanned(Action actionMessage, User unbannedUser, User unBannedBy, Group unBannedFrom) {
            super.ccGroupMemberUnBanned(actionMessage, unbannedUser, unBannedBy, unBannedFrom);
        }

        @Override
        public void ccGroupMemberScopeChanged(Action actionMessage, User updatedUser, String scopeChangedTo, String scopeChangedFrom, Group group) {
            super.ccGroupMemberScopeChanged(actionMessage, updatedUser, scopeChangedTo, scopeChangedFrom, group);
        }

        @Override
        public void ccOwnershipChanged(Group group, GroupMember newOwner) {
            super.ccOwnershipChanged(group, newOwner);
        }
    });
    ```

    Remove Listener

    ```
    CometChatGroupEvents.removeListeners();
    ```
  </Tab>
</Tabs>

### SDK Events (Real-Time, Automatic)

The component listens to these SDK events internally. No manual attachment needed unless additional side effects are required.

| SDK Listener                | Internal behavior                                    |
| --------------------------- | ---------------------------------------------------- |
| `onGroupMemberJoined`       | Updates the group list when a member joins           |
| `onGroupMemberLeft`         | Updates the group list when a member leaves          |
| `onGroupMemberKicked`       | Updates the group list when a member is kicked       |
| `onGroupMemberBanned`       | Updates the group list when a member is banned       |
| `onGroupMemberUnbanned`     | Updates the group list when a member is unbanned     |
| `onGroupMemberScopeChanged` | Updates the group list when a member's scope changes |
| `onMemberAddedToGroup`      | Updates the group list when members are added        |

> Automatic: group membership changes update the list in real time.

## Functionality

Small functional customizations such as toggling visibility of UI elements and configuring selection modes.

| Methods                     | Description                                                                 | Code                                                        |
| --------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------- |
| `setBackIconVisibility`     | Toggles visibility for the back button in the app bar                       | `.setBackIconVisibility(View.VISIBLE);`                     |
| `setToolbarVisibility`      | Toggles visibility for the toolbar in the app bar                           | `.setToolbarVisibility(View.GONE);`                         |
| `setLoadingStateVisibility` | Hides the loading state while fetching groups                               | `.setLoadingStateVisibility(View.GONE);`                    |
| `setErrorStateVisibility`   | Hides the error state on fetching groups                                    | `.setErrorStateVisibility(View.GONE);`                      |
| `setEmptyStateVisibility`   | Hides the empty state on fetching groups                                    | `.setEmptyStateVisibility(View.GONE);`                      |
| `setSeparatorVisibility`    | Controls visibility of separators in the list view                          | `.setSeparatorVisibility(View.GONE);`                       |
| `setGroupTypeVisibility`    | Controls visibility of the group type indicator (public, private, password) | `.setGroupTypeVisibility(View.GONE);`                       |
| `setSearchBoxVisibility`    | Controls visibility of the search box in the toolbar                        | `.setSearchBoxVisibility(View.GONE);`                       |
| `setSelectionMode`          | Determines the selection mode (single or multiple)                          | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
| `setSearchKeyword`          | Programmatically triggers a search with the given keyword                   | `.setSearchKeyword("design");`                              |
| `setTitleText`              | Sets a custom title in the toolbar                                          | `.setTitleText("My Groups");`                               |
| `setTitleVisibility`        | Toggles visibility for the title text in the toolbar                        | `.setTitleVisibility(View.GONE);`                           |
| `setSearchPlaceholderText`  | Sets the placeholder text for the search input                              | `.setSearchPlaceholderText("Find groups...");`              |

* **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 `Group` parameter receive the group object for that row via the `GroupsViewHolderListener` pattern (`createView` + `bindView`).

| Slot              | Method                                      | Replaces                                      |
| ----------------- | ------------------------------------------- | --------------------------------------------- |
| Leading view      | `setLeadingView(GroupsViewHolderListener)`  | Avatar / left section                         |
| Title view        | `setTitleView(GroupsViewHolderListener)`    | Name / title text                             |
| Subtitle view     | `setSubtitleView(GroupsViewHolderListener)` | Subtitle text below name                      |
| Trailing view     | `setTrailingView(GroupsViewHolderListener)` | Right section                                 |
| Item view         | `setItemView(GroupsViewHolderListener)`     | Entire list item row                          |
| Loading view      | `setLoadingView(@LayoutRes int)`            | Loading spinner                               |
| Empty view        | `setEmptyView(@LayoutRes int)`              | Empty state                                   |
| Error view        | `setErrorView(@LayoutRes int)`              | Error state                                   |
| Overflow menu     | `setOverflowMenu(View)`                     | Toolbar menu                                  |
| Options (replace) | `setOptions(Function2)`                     | Long-press context menu (replaces defaults)   |
| Options (append)  | `addOptions(Function2)`                     | Long-press context menu (appends to defaults) |

### `setLeadingView`

Replace the avatar / left section.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setLeadingView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View? {
            return null
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setLeadingView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return null;
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {

        }
    });
    ```
  </Tab>
</Tabs>

> **What this does:** Registers a `GroupsViewHolderListener` that provides a custom view for the leading (left) area of each group item. `createView` inflates your layout, and `bindView` populates it with group data.

Join status badge example:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/jpEUuHUk-hvu4tQT/images/a3c2553d-groups_leading_view-b4442c04297d7f34a5a8b00990686dc8.png?fit=max&auto=format&n=jpEUuHUk-hvu4tQT&q=85&s=854545a0a0acb8b7b3de7562d2505155" width="1280" height="800" data-path="images/a3c2553d-groups_leading_view-b4442c04297d7f34a5a8b00990686dc8.png" />
</Frame>

Create a `custom_leading_avatar_view.xml` layout:

```xml custom_leading_avatar_view.xml lines theme={null}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/leading_avatar_view"
    android:layout_width="@dimen/cometchat_40dp"
    android:layout_height="@dimen/cometchat_40dp"
    android:background="@drawable/group_leading_joined"
    android:orientation="vertical">

</LinearLayout>
```

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setLeadingView(object : GroupsViewHolderListener() {
        override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
            return LayoutInflater.from(context).inflate(R.layout.custom_leading_avatar_view, null)
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
            val groupAvatar = createdView.findViewById<LinearLayout>(R.id.leading_avatar_view)
            groupAvatar.background = if (group.isJoined) ResourcesCompat.getDrawable(
                resources,
                R.drawable.group_leading_joined,
                null
            ) else ResourcesCompat.getDrawable(
                resources,
                R.drawable.group_leading_join,
                null
            )
            groupAvatar.setOnLongClickListener { v: View? ->
                if (group.isJoined) {
                    Toast.makeText(context, "Group already joined", Toast.LENGTH_SHORT).show()
                } else {
                    Toast.makeText(context, "Joining group", Toast.LENGTH_SHORT).show()
                }
                true
            }
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setLeadingView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return LayoutInflater.from(context).inflate(R.layout.custom_leading_avatar_view, null);
        }

        @Override
        public void bindView(Context context,
                             View createdView,
                             Group group,
                             RecyclerView.ViewHolder holder,
                             List<Group> groupList,
                             int position) {
            LinearLayout groupAvatar = createdView.findViewById(R.id.leading_avatar_view);
            groupAvatar.setBackground(group.isJoined() ? ResourcesCompat.getDrawable(getResources(),
                                                                                     R.drawable.group_leading_joined,
                                                                                     null) : ResourcesCompat.getDrawable(getResources(),
                                                                                                                         R.drawable.group_leading_join,
                                                                                                                         null));
            groupAvatar.setOnLongClickListener(v -> {
                if (group.isJoined()) {
                    Toast.makeText(context, "Group already joined", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(context, "Joining group", Toast.LENGTH_SHORT).show();
                }
                return true;
            });
        }
    });
    ```
  </Tab>
</Tabs>

### `setTitleView`

Replace the name / title text.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setTitleView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View? {
            return null
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setTitleView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return null;
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {

        }
    });
    ```
  </Tab>
</Tabs>

Group type icon example:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/XgQ9DxAoWn0btB5m/images/5dab68a2-groups_title_view-8dd32ec5bab08ae58164bd47b6a863af.png?fit=max&auto=format&n=XgQ9DxAoWn0btB5m&q=85&s=9767e9cb6447c4fba7a251a9251314ae" width="1280" height="800" data-path="images/5dab68a2-groups_title_view-8dd32ec5bab08ae58164bd47b6a863af.png" />
</Frame>

Create a `custom_group_title_view.xml` layout:

```xml custom_group_title_view.xml lines theme={null}
<?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" />

    <View
        android:id="@+id/type"
        android:layout_width="wrap_content"
        android:layout_height="15dp"
        android:layout_marginStart="@dimen/cometchat_16dp"
         />

</LinearLayout>
```

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setTitleView(object : GroupsViewHolderListener() {
        override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
            return LayoutInflater.from(context).inflate(R.layout.custom_group_title_view, null)
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
            val layout = createdView.findViewById<LinearLayout>(R.id.group_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 = group.name
            val type = createdView.findViewById<View>(R.id.type)
            if (CometChatConstants.GROUP_TYPE_PUBLIC == group.groupType) {
                type.visibility = View.VISIBLE
                type.background = ResourcesCompat.getDrawable(resources, R.drawable.public_icon, null)
            } else if (CometChatConstants.GROUP_TYPE_PASSWORD == group.groupType) {
                type.visibility = View.VISIBLE
                type.background = ResourcesCompat.getDrawable(resources, R.drawable.passowrd_icon, null)
            } else if (CometChatConstants.GROUP_TYPE_PRIVATE == group.groupType) {
                type.visibility = View.VISIBLE
                type.background = ResourcesCompat.getDrawable(resources, R.drawable.private_icon, null)
            } else {
                type.visibility = View.GONE
            }
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setTitleView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return LayoutInflater.from(context).inflate(R.layout.custom_group_title_view, null);
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {
            LinearLayout layout = createdView.findViewById(R.id.user_layout);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                                                                                   ViewGroup.LayoutParams.WRAP_CONTENT);
            layout.setLayoutParams(layoutParams);
            TextView name = createdView.findViewById(R.id.title);
            name.setText(group.getName());
            View type = createdView.findViewById(R.id.type);

            if (CometChatConstants.GROUP_TYPE_PUBLIC.equals(group.getGroupType())) {
                type.setVisibility(View.VISIBLE);
                type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.public_icon, null));
            } else if (CometChatConstants.GROUP_TYPE_PASSWORD.equals(group.getGroupType())) {
                type.setVisibility(View.VISIBLE);
                type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.passowrd_icon, null));
            } else if (CometChatConstants.GROUP_TYPE_PRIVATE.equals(group.getGroupType())) {
                type.setVisibility(View.VISIBLE);
                type.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.private_icon, null));
            } else {
                type.setVisibility(View.GONE);
            }
        }
    });
    ```
  </Tab>
</Tabs>

### `setSubtitleView`

Replace the subtitle text below the group's name.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setSubtitleView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View? {
            return null
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setSubtitleView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return null;
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {

        }
    });
    ```
  </Tab>
</Tabs>

Example with member count and description:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/JSRiWiPGBHsJZFCg/images/9d2dd1ec-groups_subtitle_view-4257df0157253a4dca4cb83299b966a7.png?fit=max&auto=format&n=JSRiWiPGBHsJZFCg&q=85&s=ec23ccfb7f88cdaa0ad5dc14f61fcb20" width="1280" height="800" data-path="images/9d2dd1ec-groups_subtitle_view-4257df0157253a4dca4cb83299b966a7.png" />
</Frame>

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.setSubtitleView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View {
            return TextView(context)
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
            val textView = createdView as TextView
            textView.text =
                if (group.membersCount > 1) group.membersCount.toString() + " members" else group.membersCount.toString() + " member" + " • " + group.description
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setSubtitleView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return new TextView(context);
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {
            TextView textView = (TextView) createdView;
            textView.setText(group.getMembersCount() > 1 ? group.getMembersCount() + " members" : group.getMembersCount() + " member" + " • " + group.getDescription());
        }
    });
    ```
  </Tab>
</Tabs>

### `setTrailingView`

Replace the right section of each group item.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setTrailingView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View? {
            return null
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setTrailingView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return null;
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {

        }
    });
    ```
  </Tab>
</Tabs>

Join button example:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/NN4EdpOU3viwWMb_/images/0974e5e0-groups_trailing_view-ab39b3abd09b63c46d7e95c2e6d21b4d.png?fit=max&auto=format&n=NN4EdpOU3viwWMb_&q=85&s=460070c2426b32afee3b8da7dd8fdba6" width="1280" height="800" data-path="images/0974e5e0-groups_trailing_view-ab39b3abd09b63c46d7e95c2e6d21b4d.png" />
</Frame>

Create a `custom_tail_view.xml` layout:

```xml custom_tail_view.xml lines theme={null}
<?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"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="#EDEAFA"
        android:text="+ joined"
        android:textStyle="bold"
        android:textAppearance="?attr/cometchatTextAppearanceCaption2Regular"
        android:textAllCaps="true"
        android:textColor="#6852D6"
        app:cornerRadius="@dimen/cometchat_1000dp" />
</LinearLayout>
```

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setTrailingView(object : GroupsViewHolderListener() {
        override fun createView(context: Context?, listItem: CometchatListBaseItemsBinding?): View {
            return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null)
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
            val button = createdView.findViewById<MaterialButton>(R.id.button)
            button.text = (if (group.isJoined) "Joined" else "+ Join")
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setTrailingView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return LayoutInflater.from(context).inflate(R.layout.custom_tail_view, null);
        }

        @Override
        public void bindView(Context context,
                             View createdView,
                             Group group,
                             RecyclerView.ViewHolder holder,
                             List<Group> groupList,
                             int position) {
             MaterialButton button = createdView.findViewById(R.id.button);
            button.setText(group.isJoined() ? "Joined" : "+ Join");
        }
    });
    ```
  </Tab>
</Tabs>

### `setItemView`

Replace the entire list item row.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setItemView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View? {
            return null
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setItemView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return null;
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {

        }
    });
    ```
  </Tab>
</Tabs>

Custom list item example:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/2JiXkJ8lq6PmPGlJ/images/6c5fc063-groups_list_item_view-2567373b1b5f9faf6c29be8d07a1a274.png?fit=max&auto=format&n=2JiXkJ8lq6PmPGlJ&q=85&s=2acf97adad6e7f67cb107058d1ef714e" width="1280" height="800" data-path="images/6c5fc063-groups_list_item_view-2567373b1b5f9faf6c29be8d07a1a274.png" />
</Frame>

Create a `custom_group_list_item.xml` layout:

```xml custom_group_list_item.xml lines theme={null}
<?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">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

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

        <com.google.android.material.card.MaterialCardView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/cometchat_16dp"
            android:layout_marginTop="@dimen/cometchat_2dp"
            android:layout_marginBottom="@dimen/cometchat_2dp"
            android:elevation="0dp"
            app:cardBackgroundColor="#EDEAFA"
            app:cardCornerRadius="@dimen/cometchat_radius_max"
            app:cardElevation="0dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/cometchat_margin_3"
                android:layout_marginTop="@dimen/cometchat_margin_1"
                android:layout_marginEnd="@dimen/cometchat_margin_3"
                android:layout_marginBottom="@dimen/cometchat_margin_1"
                android:text="JOIN"
                android:textAppearance="@style/CometChatTextAppearanceCaption1.Medium"
                android:textColor="?attr/cometchatPrimaryColor" />
        </com.google.android.material.card.MaterialCardView>
    </LinearLayout>

    <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>
```

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    cometchatGroups.setItemView(object : GroupsViewHolderListener() {
        override fun createView(
            context: Context?,
            listItem: CometchatListBaseItemsBinding?
        ): View {
            return View.inflate(context, R.layout.custom_group_list_item, null)
        }

        override fun bindView(
            context: Context,
            createdView: View,
            group: Group,
            holder: RecyclerView.ViewHolder,
            groupList: List<Group>,
            position: Int
        ) {
            val groupName = createdView.findViewById<TextView>(R.id.tvName)
            val groupMemberCount = createdView.findViewById<TextView>(R.id.tvSubtitle)
            val params = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
            )
            createdView.layoutParams = params
            groupName.text = group.name
            groupMemberCount.text =
                if (group.membersCount > 1) group.membersCount.toString() + " members" else group.membersCount.toString() + " member" + " • " + group.description
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    cometchatGroups.setItemView(new GroupsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatListBaseItemsBinding listItem) {
            return View.inflate(context, R.layout.custom_group_list_item, null);
        }

        @Override
        public void bindView(Context context, View createdView, Group group, RecyclerView.ViewHolder holder, List<Group> groupList, int position) {
            TextView groupName = createdView.findViewById(R.id.tvName);
            TextView groupMemberCount = createdView.findViewById(R.id.tvSubtitle);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            createdView.setLayoutParams(params);
            groupName.setText(group.getName());
            groupMemberCount.setText(group.getMembersCount() > 1 ? group.getMembersCount() + " members" : group.getMembersCount() + " member" + " • " + group.getDescription());
        }
    });
    ```
  </Tab>
</Tabs>

### `setOptions`

Replace the long-press context menu entirely.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.options = Function2<Context?, Group?, List<CometChatPopupMenu.MenuItem?>?> { context, group -> emptyList<CometChatPopupMenu.MenuItem?>() }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setOptions((context, group) -> Collections.emptyList());
    ```
  </Tab>
</Tabs>

### `addOptions`

Append to the long-press context menu without removing defaults.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.addOptions { context, group -> emptyList<CometChatPopupMenu.MenuItem?>() }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.addOptions((context, group) -> Collections.emptyList());
    ```
  </Tab>
</Tabs>

### `setLoadingView`

Sets a custom loading view displayed when data is being fetched.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.loadingView = R.layout.your_loading_view
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setLoadingView(R.layout.your_loading_view);
    ```
  </Tab>
</Tabs>

### `setEmptyView`

Configures a custom view displayed when there are no groups in the list.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.emptyView = R.layout.your_empty_view
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setEmptyView(R.layout.your_empty_view);
    ```
  </Tab>
</Tabs>

### `setErrorView`

Defines a custom error state view that appears when an issue occurs while loading groups.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.errorView = R.layout.your_error_view
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setErrorView(R.layout.your_error_view);
    ```
  </Tab>
</Tabs>

### `setOverflowMenu`

Replace the toolbar overflow menu.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/2JiXkJ8lq6PmPGlJ/images/6f8b7200-groups_menu-abd299ecf561c71932941257525ea004.png?fit=max&auto=format&n=2JiXkJ8lq6PmPGlJ&q=85&s=7c1dd5b7b9eaead2f1ef39e6594092f8" width="1280" height="800" data-path="images/6f8b7200-groups_menu-abd299ecf561c71932941257525ea004.png" />
</Frame>

Create an `overflow_menu_layout.xml` layout:

```xml overflow_menu_layout.xml lines theme={null}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/ivMenu"
        android:layout_width="@dimen/cometchat_24dp"
        android:layout_height="@dimen/cometchat_24dp"
        android:layout_marginStart="@dimen/cometchat_margin_4"
        android:importantForAccessibility="no"
        android:src="@drawable/ic_create_group" />

</LinearLayout>
```

<Tabs>
  <Tab title="Kotlin">
    ```kotlin YourActivity.kt lines theme={null}
    val view: View = layoutInflater.inflate(R.layout.overflow_menu_layout, null)
    val imgRefresh = view.findViewById<ImageView>(R.id.ivMenu)
    imgRefresh.setOnClickListener { v: View? ->
        Toast.makeText(requireContext(), "Clicked on Refresh", Toast.LENGTH_SHORT).show()
    }
    cometchatGroups.setOverflowMenu(view)
    ```
  </Tab>

  <Tab title="Java">
    ```java YourActivity.java lines theme={null}
    View view = getLayoutInflater().inflate(R.layout.overflow_menu_layout, null);
    ImageView imgRefresh = view.findViewById(R.id.ivMenu);
    imgRefresh.setOnClickListener(v -> {
        Toast.makeText(requireContext(), "Clicked on Refresh", Toast.LENGTH_SHORT).show();
    });
    cometchatGroups.setOverflowMenu(view);
    ```
  </Tab>
</Tabs>

* **Verify**: After setting any custom view slot, confirm the custom view renders in the correct position within the group list item, and the data binding populates correctly for each group.

## Common Patterns

### Hide all chrome — minimal list

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setGroupTypeVisibility(View.GONE)
    cometchatGroups.setSeparatorVisibility(View.GONE)
    cometchatGroups.setToolbarVisibility(View.GONE)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setGroupTypeVisibility(View.GONE);
    cometchatGroups.setSeparatorVisibility(View.GONE);
    cometchatGroups.setToolbarVisibility(View.GONE);
    ```
  </Tab>
</Tabs>

### Joined groups only

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    val builder = GroupsRequestBuilder()
        .joinedOnly(true)
    cometchatGroups.setGroupsRequestBuilder(builder)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder()
        .joinedOnly(true);
    cometchatGroups.setGroupsRequestBuilder(builder);
    ```
  </Tab>
</Tabs>

### Filter by tags

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    val builder = GroupsRequestBuilder()
        .setTags(listOf("vip", "premium"))
    cometchatGroups.setGroupsRequestBuilder(builder)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    GroupsRequest.GroupsRequestBuilder builder = new GroupsRequest.GroupsRequestBuilder()
        .setTags(Arrays.asList("vip", "premium"));
    cometchatGroups.setGroupsRequestBuilder(builder);
    ```
  </Tab>
</Tabs>

## Advanced Methods

### Programmatic Selection

#### `selectGroup`

Programmatically selects or deselects a group. Works with both `SINGLE` and `MULTIPLE` selection modes.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    // Select a group in single-select mode
    cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.SINGLE)

    // Select a group in multi-select mode
    cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.MULTIPLE)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    // Select a group in single-select mode
    cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.SINGLE);

    // Select a group in multi-select mode
    cometchatGroups.selectGroup(group, UIKitConstants.SelectionMode.MULTIPLE);
    ```
  </Tab>
</Tabs>

> In `SINGLE` mode, selecting a new group replaces the previous selection. In `MULTIPLE` mode, calling this on an already-selected group deselects it (toggle behavior).

#### `clearSelection`

Clears all selected groups and resets the selection UI.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.clearSelection()
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.clearSelection();
    ```
  </Tab>
</Tabs>

#### `getSelectedGroups`

Returns the list of currently selected `Group` objects.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    val selected = cometchatGroups.selectedGroups
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    List<Group> selected = cometchatGroups.getSelectedGroups();
    ```
  </Tab>
</Tabs>

### Selected Groups List

When using multi-select mode, a horizontal list of selected groups can be shown above the main list.

| Method                               | Type                             | Description                              |
| ------------------------------------ | -------------------------------- | ---------------------------------------- |
| `setSelectedGroupsListVisibility`    | `int (View.VISIBLE / View.GONE)` | Show or hide the selected groups strip   |
| `setSelectedGroupAvatarStyle`        | `@StyleRes int`                  | Avatar style for selected group chips    |
| `setSelectedGroupItemTextColor`      | `@ColorInt int`                  | Text color for selected group names      |
| `setSelectedGroupItemTextAppearance` | `@StyleRes int`                  | Text appearance for selected group names |
| `setSelectedGroupItemRemoveIcon`     | `Drawable`                       | Icon for the remove button on each chip  |
| `setSelectedGroupItemRemoveIconTint` | `@ColorInt int`                  | Tint color for the remove icon           |

### Search Input Customization

The built-in search box can be customized programmatically:

| Method                                    | Type             | Description                                    |
| ----------------------------------------- | ---------------- | ---------------------------------------------- |
| `setSearchPlaceholderText`                | `String`         | Sets the placeholder text for the search input |
| `setSearchInputTextColor`                 | `@ColorInt int`  | Text color of the search input                 |
| `setSearchInputTextAppearance`            | `@StyleRes int`  | Text appearance of the search input            |
| `setSearchInputPlaceHolderTextColor`      | `@ColorInt int`  | Placeholder text color                         |
| `setSearchInputPlaceHolderTextAppearance` | `@StyleRes int`  | Placeholder text appearance                    |
| `setSearchInputIcon`                      | `Drawable`       | Leading icon in the search box                 |
| `setSearchInputIconTint`                  | `@ColorInt int`  | Tint for the leading icon                      |
| `setSearchInputEndIcon`                   | `Drawable`       | Trailing icon in the search box                |
| `setSearchInputEndIconTint`               | `@ColorInt int`  | Tint for the trailing icon                     |
| `setSearchInputStrokeWidth`               | `@Dimension int` | Stroke width of the search box border          |
| `setSearchInputStrokeColor`               | `@ColorInt int`  | Stroke color of the search box border          |
| `setSearchInputBackgroundColor`           | `@ColorInt int`  | Background color of the search box             |
| `setSearchInputCornerRadius`              | `@Dimension int` | Corner radius of the search box                |

### Internal Access

These methods provide direct access to internal components for advanced use cases.

| Method                      | Returns                     | Description                                     |
| --------------------------- | --------------------------- | ----------------------------------------------- |
| `getBinding()`              | `CometchatGroupListBinding` | The ViewBinding for the component's root layout |
| `getViewModel()`            | `GroupsViewModel`           | The ViewModel managing group data and state     |
| `getAdapter()`              | `GroupsAdapter`             | The adapter powering the RecyclerView           |
| `setAdapter(GroupsAdapter)` | `void`                      | Replaces the default adapter with a custom one  |

> 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 `CometChatGroupsStyle` in `themes.xml`, then apply with `setStyle()`.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/XgQ9DxAoWn0btB5m/images/5b3c1825-groups_styling-f8164f3a9b1247ad1db859328c199051.png?fit=max&auto=format&n=XgQ9DxAoWn0btB5m&q=85&s=241addf3bc97d623dfcb400b1825841e" width="1280" height="800" data-path="images/5b3c1825-groups_styling-f8164f3a9b1247ad1db859328c199051.png" />
</Frame>

```xml themes.xml lines theme={null}
    <style name="CustomAvatarStyle" parent="CometChatAvatarStyle">
        <item name="cometchatAvatarStrokeRadius">8dp</item>
        <item name="cometchatAvatarBackgroundColor">#FBAA75</item>
    </style>
    <style name="CustomGroupsStyle" parent="CometChatGroupsStyle">
        <item name="cometchatGroupsAvatar">@style/CustomAvatarStyle</item>
        <item name="cometchatGroupsSeparatorColor">#F76808</item>
        <item name="cometchatGroupsTitleTextColor">#F76808</item>
    </style>
```

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    cometchatGroups.setStyle(R.style.CustomGroupsStyle)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    cometchatGroups.setStyle(R.style.CustomGroupsStyle);
    ```
  </Tab>
</Tabs>

To know more such attributes, visit the [attributes file](https://github.com/cometchat/cometchat-uikit-android/blob/v5/chatuikit/src/main/res/values/attr_cometchat_groups.xml).

### Programmatic Style Properties

In addition to XML theme styles, the component exposes programmatic setters for fine-grained control:

| Method                                | Type             | Description                                  |
| ------------------------------------- | ---------------- | -------------------------------------------- |
| `setBackgroundColor`                  | `@ColorInt int`  | Background color of the component            |
| `setBackIconTint`                     | `@ColorInt int`  | Tint color for the back icon                 |
| `setBackIcon`                         | `Drawable`       | Custom back icon drawable                    |
| `setTitleTextColor`                   | `@ColorInt int`  | Title text color in the toolbar              |
| `setTitleTextAppearance`              | `@StyleRes int`  | Title text appearance in the toolbar         |
| `setItemTitleTextColor`               | `@ColorInt int`  | Text color for group item titles             |
| `setItemTitleTextAppearance`          | `@StyleRes int`  | Text appearance for group item titles        |
| `setItemBackgroundColor`              | `@ColorInt int`  | Background color for list items              |
| `setItemSelectedBackgroundColor`      | `@ColorInt int`  | Background color for selected list items     |
| `setSeparatorColor`                   | `@ColorInt int`  | Color of list item separators                |
| `setStrokeColor`                      | `@ColorInt int`  | Stroke color of the component border         |
| `setStrokeWidth`                      | `@Dimension int` | Stroke width of the component border         |
| `setCornerRadius`                     | `@Dimension int` | Corner radius of the component               |
| `setSubtitleTextColor`                | `@ColorInt int`  | Text color for group item subtitles          |
| `setSubtitleTextAppearance`           | `@StyleRes int`  | Text appearance for group item subtitles     |
| `setEmptyStateTextColor`              | `@ColorInt int`  | Title text color for the empty state         |
| `setEmptyStateTextAppearance`         | `@StyleRes int`  | Title text appearance for the empty state    |
| `setEmptyStateSubtitleTextColor`      | `@ColorInt int`  | Subtitle text color for the empty state      |
| `setEmptyStateSubTitleTextAppearance` | `@StyleRes int`  | Subtitle text appearance for the empty state |
| `setErrorStateTextColor`              | `@ColorInt int`  | Title text color for the error state         |
| `setErrorStateTextAppearance`         | `@StyleRes int`  | Title text appearance for the error state    |
| `setErrorStateSubtitleColor`          | `@ColorInt int`  | Subtitle text color for the error state      |
| `setErrorStateSubtitleTextAppearance` | `@StyleRes int`  | Subtitle text appearance for the error state |
| `setRetryButtonTextColor`             | `@ColorInt int`  | Text color for the retry button              |
| `setRetryButtonTextAppearance`        | `@StyleRes int`  | Text appearance for the retry button         |
| `setRetryButtonBackgroundColor`       | `@ColorInt int`  | Background color for the retry button        |
| `setRetryButtonStrokeColor`           | `@ColorInt int`  | Stroke color for the retry button            |
| `setRetryButtonStrokeWidth`           | `@Dimension int` | Stroke width for the retry button            |
| `setRetryButtonCornerRadius`          | `@Dimension int` | Corner radius for the retry button           |
| `setAvatarStyle`                      | `@StyleRes int`  | Style for group avatars                      |
| `setStatusIndicatorStyle`             | `@StyleRes int`  | Style for group type status indicators       |

### Checkbox Style Properties (Selection Mode)

When using `SINGLE` or `MULTIPLE` selection mode, checkboxes appear on each item:

| Method                              | Type             | Description                            |
| ----------------------------------- | ---------------- | -------------------------------------- |
| `setCheckBoxStrokeWidth`            | `@Dimension int` | Stroke width of the checkbox border    |
| `setCheckBoxCornerRadius`           | `@Dimension int` | Corner radius of the checkbox          |
| `setCheckBoxStrokeColor`            | `@ColorInt int`  | Stroke color of the checkbox border    |
| `setCheckBoxBackgroundColor`        | `@ColorInt int`  | Background color of unchecked checkbox |
| `setCheckBoxCheckedBackgroundColor` | `@ColorInt int`  | Background color of checked checkbox   |
| `setCheckBoxSelectIcon`             | `Drawable`       | Icon shown when checkbox is checked    |
| `setCheckBoxSelectIconTint`         | `@ColorInt int`  | Tint for the checkbox select icon      |
| `setDiscardSelectionIcon`           | `Drawable`       | Icon for the discard selection button  |
| `setDiscardSelectionIconTint`       | `@ColorInt int`  | Tint for the discard selection icon    |
| `setSubmitSelectionIcon`            | `Drawable`       | Icon for the submit selection button   |
| `setSubmitSelectionIconTint`        | `@ColorInt int`  | Tint for the submit selection icon     |

## Customization Matrix

| What to change                           | Where             | Property/API                                | Example                                                     |
| ---------------------------------------- | ----------------- | ------------------------------------------- | ----------------------------------------------------------- |
| Override behavior on group interaction   | Activity/Fragment | `setOn<Event>` callbacks                    | `setOnItemClick((v, pos, g) -> { ... })`                    |
| Filter which groups appear               | Activity/Fragment | `setGroupsRequestBuilder`                   | `setGroupsRequestBuilder(builder)`                          |
| Customize search results                 | Activity/Fragment | `setSearchRequestBuilder`                   | `setSearchRequestBuilder(builder)`                          |
| Toggle visibility of UI elements         | Activity/Fragment | `set<Feature>Visibility(int)`               | `setGroupTypeVisibility(View.GONE)`                         |
| Replace a section of the list item       | Activity/Fragment | `set<Slot>View`                             | `setLeadingView(listener)`                                  |
| Change colors, fonts, spacing            | `themes.xml`      | `CometChatGroupsStyle`                      | `<item name="cometchatGroupsSeparatorColor">#F76808</item>` |
| Avatar style (corner radius, background) | `themes.xml`      | `cometchatGroupsAvatar`                     | `<item name="cometchatAvatarStrokeRadius">8dp</item>`       |
| Apply a custom style                     | Activity/Fragment | `setStyle(int styleRes)`                    | `cometchatGroups.setStyle(R.style.CustomGroupsStyle);`      |
| Back button visibility                   | Activity/Fragment | `setBackIconVisibility(int)`                | `.setBackIconVisibility(View.VISIBLE);`                     |
| Toolbar visibility                       | Activity/Fragment | `setToolbarVisibility(int)`                 | `.setToolbarVisibility(View.GONE);`                         |
| Error state visibility                   | Activity/Fragment | `setErrorStateVisibility(int)`              | `.setErrorStateVisibility(View.GONE);`                      |
| Empty state visibility                   | Activity/Fragment | `setEmptyStateVisibility(int)`              | `.setEmptyStateVisibility(View.GONE);`                      |
| Loading state visibility                 | Activity/Fragment | `setLoadingStateVisibility(int)`            | `.setLoadingStateVisibility(View.GONE);`                    |
| Separator visibility                     | Activity/Fragment | `setSeparatorVisibility(int)`               | `.setSeparatorVisibility(View.GONE);`                       |
| Group type indicator visibility          | Activity/Fragment | `setGroupTypeVisibility(int)`               | `.setGroupTypeVisibility(View.GONE);`                       |
| Selection mode (single/multiple)         | Activity/Fragment | `setSelectionMode(SelectionMode)`           | `.setSelectionMode(UIKitConstants.SelectionMode.MULTIPLE);` |
| Search keyword                           | Activity/Fragment | `setSearchKeyword(String)`                  | `.setSearchKeyword("design");`                              |
| Search box visibility                    | Activity/Fragment | `setSearchBoxVisibility(int)`               | `.setSearchBoxVisibility(View.GONE);`                       |
| Custom toolbar title                     | Activity/Fragment | `setTitleText(String)`                      | `.setTitleText("My Groups");`                               |
| Title visibility                         | Activity/Fragment | `setTitleVisibility(int)`                   | `.setTitleVisibility(View.GONE);`                           |
| Search placeholder                       | Activity/Fragment | `setSearchPlaceholderText(String)`          | `.setSearchPlaceholderText("Find groups...");`              |
| Long-press options (replace)             | Activity/Fragment | `setOptions(Function2)`                     | See `setOptions` code above                                 |
| Long-press options (append)              | Activity/Fragment | `addOptions(Function2)`                     | See `addOptions` code above                                 |
| Loading view                             | Activity/Fragment | `setLoadingView(int)`                       | `.setLoadingView(R.layout.your_loading_view);`              |
| Empty view                               | Activity/Fragment | `setEmptyView(int)`                         | `.setEmptyView(R.layout.your_empty_view);`                  |
| Error view                               | Activity/Fragment | `setErrorView(int)`                         | `.setErrorView(R.layout.your_error_view);`                  |
| Leading view (avatar area)               | Activity/Fragment | `setLeadingView(GroupsViewHolderListener)`  | See `setLeadingView` code above                             |
| Title view                               | Activity/Fragment | `setTitleView(GroupsViewHolderListener)`    | See `setTitleView` code above                               |
| Trailing view                            | Activity/Fragment | `setTrailingView(GroupsViewHolderListener)` | See `setTrailingView` code above                            |
| Entire list item                         | Activity/Fragment | `setItemView(GroupsViewHolderListener)`     | See `setItemView` code above                                |
| Subtitle view                            | Activity/Fragment | `setSubtitleView(GroupsViewHolderListener)` | See `setSubtitleView` code above                            |
| Overflow menu                            | Activity/Fragment | `setOverflowMenu(View)`                     | `cometchatGroups.setOverflowMenu(view);`                    |
| Programmatic selection                   | Activity/Fragment | `selectGroup(Group, SelectionMode)`         | `.selectGroup(group, SelectionMode.SINGLE);`                |
| Clear selection                          | Activity/Fragment | `clearSelection()`                          | `.clearSelection();`                                        |
| Selected groups strip                    | Activity/Fragment | `setSelectedGroupsListVisibility(int)`      | `.setSelectedGroupsListVisibility(View.VISIBLE);`           |
| Internal adapter access                  | Activity/Fragment | `getAdapter()` / `setAdapter()`             | Advanced use only                                           |

## Next Steps

<CardGroup cols={2}>
  <Card title="Conversations" icon="comments" href="/ui-kit/android/conversations">
    Browse recent conversations
  </Card>

  <Card title="Users" icon="user" href="/ui-kit/android/users">
    Browse and search available users
  </Card>

  <Card title="Group Members" icon="user-group" href="/ui-kit/android/group-members">
    View and manage group members
  </Card>

  <Card title="Message List" icon="messages" href="/ui-kit/android/message-list">
    Display messages in a conversation
  </Card>
</CardGroup>
