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

# View Slots

> Replace specific regions of a component's UI using the ViewHolderListener pattern without rebuilding the entire component.

View Slots let you swap out specific parts of a component's list item — the avatar area, title, subtitle, trailing section, or the entire row — while keeping the rest of the component's behavior intact.

## The ViewHolderListener Pattern

Every list-based component defines a `ViewHolderListener` abstract class (e.g., `ConversationsViewHolderListener`) with two callbacks:

| Callback                                                                                                                                                    | Purpose                                                                                                                                                                                                      |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `createView(Context context, CometchatConversationsListItemsBinding listItem)`                                                                              | Return a `View` that will be placed in the slot. Called once when the ViewHolder is created.                                                                                                                 |
| `bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List<Conversation> conversationList, int position)` | Bind data to your custom view. Called every time the item is bound (scroll, update). `createdView` is the view returned by `createView`, and the full conversation list and holder are provided for context. |

## Available View Slots

| Setter            | Region        | Description                                           |
| ----------------- | ------------- | ----------------------------------------------------- |
| `setLeadingView`  | Left section  | Replaces the avatar / leading area of each list item. |
| `setTitleView`    | Title text    | Replaces the name / title text area.                  |
| `setSubtitleView` | Subtitle text | Replaces the last message preview area.               |
| `setTrailingView` | Right section | Replaces the timestamp / badge / trailing area.       |
| `setItemView`     | Entire row    | Replaces the entire list item layout.                 |

## Slot-Level vs Full Item Replacement

Use slot-level setters (`setLeadingView`, `setTitleView`, `setSubtitleView`, `setTrailingView`) when you want to customize one region while keeping the default layout for everything else. Use `setItemView` when you need complete control over the entire row layout.

<Warning>
  When you use `setItemView`, all other slot setters are ignored since the entire row is replaced.
</Warning>

## Example: Custom Leading View

Replace the default avatar with a custom view that shows the first letter of the conversation name in a colored circle:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    conversations.setLeadingView(object : ConversationsViewHolderListener() {
        override fun createView(
            context: Context,
            listItem: CometchatConversationsListItemsBinding
        ): View {
            val textView = TextView(context).apply {
                layoutParams = ViewGroup.LayoutParams(48.dp, 48.dp)
                gravity = Gravity.CENTER
                textSize = 18f
                setTextColor(Color.WHITE)
            }
            return textView
        }

        override fun bindView(
            context: Context,
            createdView: View,
            conversation: Conversation,
            holder: RecyclerView.ViewHolder,
            conversationList: List<Conversation>,
            position: Int
        ) {
            val textView = createdView as TextView
            val name = conversation.conversationWith?.name ?: ""
            textView.text = name.firstOrNull()?.uppercase() ?: "?"
            textView.background = GradientDrawable().apply {
                shape = GradientDrawable.OVAL
                setColor(Color.parseColor("#6851D6"))
            }
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    conversations.setLeadingView(new ConversationsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
            TextView textView = new TextView(context);
            textView.setLayoutParams(new ViewGroup.LayoutParams(48, 48));
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(18f);
            textView.setTextColor(Color.WHITE);
            return textView;
        }

        @Override
        public void bindView(Context context, View createdView, Conversation conversation,
                RecyclerView.ViewHolder holder, List<Conversation> conversationList, int position) {
            TextView textView = (TextView) createdView;
            String name = conversation.getConversationWith() != null
                ? conversation.getConversationWith().getName() : "";
            String initial = name.isEmpty() ? "?" : String.valueOf(name.charAt(0)).toUpperCase();
            textView.setText(initial);
            GradientDrawable bg = new GradientDrawable();
            bg.setShape(GradientDrawable.OVAL);
            bg.setColor(Color.parseColor("#6851D6"));
            textView.setBackground(bg);
        }
    });
    ```
  </Tab>
</Tabs>

## Example: Custom Subtitle View

Show a "typing..." indicator or a custom last message format in the subtitle area:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    conversations.setSubtitleView(object : ConversationsViewHolderListener() {
        override fun createView(
            context: Context,
            listItem: CometchatConversationsListItemsBinding
        ): View {
            return TextView(context).apply {
                maxLines = 1
                ellipsize = TextUtils.TruncateAt.END
            }
        }

        override fun bindView(
            context: Context,
            createdView: View,
            conversation: Conversation,
            holder: RecyclerView.ViewHolder,
            conversationList: List<Conversation>,
            position: Int
        ) {
            val textView = createdView as TextView
            val lastMessage = conversation.lastMessage
            textView.text = when (lastMessage) {
                is TextMessage -> lastMessage.text
                is MediaMessage -> "📎 ${lastMessage.attachment?.fileExtension ?: "Media"}"
                else -> "New conversation"
            }
        }
    })
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    conversations.setSubtitleView(new ConversationsViewHolderListener() {
        @Override
        public View createView(Context context, CometchatConversationsListItemsBinding listItem) {
            TextView textView = new TextView(context);
            textView.setMaxLines(1);
            textView.setEllipsize(TextUtils.TruncateAt.END);
            return textView;
        }

        @Override
        public void bindView(Context context, View createdView, Conversation conversation,
                RecyclerView.ViewHolder holder, List<Conversation> conversationList, int position) {
            TextView textView = (TextView) createdView;
            BaseMessage lastMessage = conversation.getLastMessage();
            String subtitle;
            if (lastMessage instanceof TextMessage) {
                subtitle = ((TextMessage) lastMessage).getText();
            } else if (lastMessage instanceof MediaMessage) {
                subtitle = "Media";
            } else {
                subtitle = "New conversation";
            }
            textView.setText(subtitle);
        }
    });
    ```
  </Tab>
</Tabs>

## Toolbar Overflow Menu

Use `setOverflowMenu(View)` to inject a custom view into the component's toolbar area. This is separate from the list item view slots — it customizes the toolbar, not individual rows.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val menuButton = ImageButton(context).apply {
        setImageResource(R.drawable.ic_filter)
        setOnClickListener { /* show filter dialog */ }
    }
    conversations.setOverflowMenu(menuButton)
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    ImageButton menuButton = new ImageButton(context);
    menuButton.setImageResource(R.drawable.ic_filter);
    menuButton.setOnClickListener(v -> { /* show filter dialog */ });
    conversations.setOverflowMenu(menuButton);
    ```
  </Tab>
</Tabs>

## Related

* [Adapter Customization](/ui-kit/android/customization-adapters) — View slot setters are also available directly on the Adapter.
* [Customization Overview](/ui-kit/android/customization-overview) — See all customization categories.
