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

# Conversations

> Scrollable list of recent one-on-one and group conversations for the logged-in user with real-time updates.

<Accordion title="AI Integration Quick Reference">
  ```json theme={null}
  {
    "component": "CometChatConversations",
    "package": "@cometchat/chat-uikit-react",
    "import": "import { CometChatConversations } from \"@cometchat/chat-uikit-react\";",
    "description": "Scrollable list of recent one-on-one and group conversations for the logged-in user with real-time updates.",
    "cssRootClass": ".cometchat-conversations",
    "primaryOutput": {
      "prop": "onItemClick",
      "type": "(conversation: CometChat.Conversation) => void"
    },
    "props": {
      "data": {
        "conversationsRequestBuilder": {
          "type": "CometChat.ConversationsRequestBuilder",
          "default": "SDK default (30 per page)",
          "note": "Pass the builder instance, not the result of .build()"
        },
        "searchRequestBuilder": {
          "type": "CometChat.ConversationsRequestBuilder",
          "default": "undefined"
        },
        "searchKeyword": {
          "type": "string",
          "default": "undefined"
        },
        "activeConversation": {
          "type": "CometChat.Conversation",
          "default": "undefined"
        },
        "lastMessageDateTimeFormat": {
          "type": "CometChatDateFormatConfig",
          "default": "hh:mm A today, Yesterday, dddd last week, DD/MM/YYYY older"
        }
      },
      "callbacks": {
        "onItemClick": "(conversation: CometChat.Conversation) => void",
        "onSelect": "(conversation: CometChat.Conversation, selected: boolean) => void",
        "onError": "((error: CometChat.CometChatException) => void) | null",
        "onEmpty": "() => void",
        "onSearchBarClicked": "() => void"
      },
      "visibility": {
        "hideReceipts": { "type": "boolean", "default": false },
        "hideUserStatus": { "type": "boolean", "default": false },
        "hideGroupType": { "type": "boolean", "default": false },
        "hideUnreadCount": { "type": "boolean", "default": false },
        "hideDeleteConversation": { "type": "boolean", "default": false },
        "showSearchBar": { "type": "boolean", "default": true },
        "showScrollbar": { "type": "boolean", "default": false }
      },
      "sound": {
        "disableSoundForMessages": { "type": "boolean", "default": false },
        "customSoundForMessages": { "type": "string", "default": "built-in" }
      },
      "selection": {
        "selectionMode": {
          "type": "CometChatConversationsSelectionMode",
          "values": ["'none'", "'single'", "'multiple'"],
          "default": "'none'"
        }
      },
      "viewSlots": {
        "itemView": "(conversation: CometChat.Conversation) => ReactNode",
        "leadingView": "(conversation: CometChat.Conversation) => ReactNode",
        "titleView": "(conversation: CometChat.Conversation) => ReactNode",
        "subtitleView": "(conversation: CometChat.Conversation) => ReactNode",
        "trailingView": "(conversation: CometChat.Conversation) => ReactNode",
        "headerView": "ReactNode",
        "searchView": "ReactNode",
        "loadingView": "ReactNode",
        "emptyView": "ReactNode",
        "errorView": "ReactNode",
        "options": "(conversation: CometChat.Conversation) => CometChatConversationOption[]"
      }
    },
    "events": [
      {
        "name": "ui:conversation/deleted",
        "payload": "{ conversation: CometChat.Conversation }",
        "description": "Conversation deleted from list"
      }
    ],
    "sdkListeners": [
      "onTextMessageReceived",
      "onMediaMessageReceived",
      "onCustomMessageReceived",
      "onInteractiveMessageReceived",
      "onTypingStarted",
      "onTypingEnded",
      "onMessagesDelivered",
      "onMessagesRead",
      "onUserOnline",
      "onUserOffline",
      "onGroupMemberJoined",
      "onGroupMemberLeft",
      "onGroupMemberKicked",
      "onGroupMemberBanned",
      "onMemberAddedToGroup"
    ],
    "types": {
      "CometChatDateFormatConfig": {
        "today": "string | undefined",
        "yesterday": "string | undefined",
        "lastWeek": "string | undefined",
        "otherDays": "string | undefined",
        "relativeTime": {
          "minute": "string | undefined",
          "minutes": "string | undefined",
          "hour": "string | undefined",
          "hours": "string | undefined"
        }
      },
      "CometChatConversationOption": {
        "id": "string",
        "title": "string",
        "iconURL": "string | undefined",
        "onClick": "(conversation: CometChat.Conversation) => void"
      },
      "CometChatConversationsSelectionMode": "'none' | 'single' | 'multiple'"
    }
  }
  ```
</Accordion>

## Overview

`CometChatConversations` is a sidebar list component. It renders recent conversations for the logged-in user and emits the selected `CometChat.Conversation` via `onItemClick`. Wire it to `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to build a standard two-panel chat layout.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/9bgr-iIAUJixmNKk/images/two_panel_layout_without_tabs_react_v7.png?fit=max&auto=format&n=9bgr-iIAUJixmNKk&q=85&s=a9bc1857634b0c3d6451293ade1cba41" width="1440" height="800" data-path="images/two_panel_layout_without_tabs_react_v7.png" />
</Frame>

<Info>
  **Live Preview** — interact with the default conversations list.

  [Open in Storybook ↗](https://storybook.cometchat.io/react/?path=/story/components-conversations-cometchat-conversations--default)
</Info>

<iframe src="https://storybook.cometchat.io/react/iframe.html?id=components-conversations-cometchat-conversations--default&viewMode=story&shortcuts=false&singleStory=true" className="w-full rounded-xl" loading="lazy" style={{height: "700px", border: "1px solid #e0e0e0"}} title="CometChatConversations — Default" allow="clipboard-write" />

The component handles:

* Paginated fetching with infinite scroll
* Real-time updates (new messages, typing indicators, presence changes)
* Search filtering
* Selection mode (single/multiple)

***

## Usage

### Flat API

```tsx theme={null}
import { CometChatConversations } from "@cometchat/chat-uikit-react";

function Sidebar() {
  return (
    <CometChatConversations
      onItemClick={(conversation) => {
        const entity = conversation.getConversationWith();
        // Pass entity to MessageHeader, MessageList, MessageComposer
      }}
    />
  );
}
```

### Compound Composition

```tsx theme={null}
import { CometChatConversations } from "@cometchat/chat-uikit-react";

function Sidebar() {
  return (
    <CometChatConversations.Root onItemClick={handleClick}>
      <CometChatConversations.Header title="Messages" />
      <CometChatConversations.SearchBar placeholder="Find a conversation..." />
      <CometChatConversations.LoadingState />
      <CometChatConversations.ErrorState />
      <CometChatConversations.EmptyState>
        <p>No conversations yet. Start a new chat!</p>
      </CometChatConversations.EmptyState>
      <CometChatConversations.List />
    </CometChatConversations.Root>
  );
}
```

### Full Layout Example

```tsx theme={null}
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
  CometChatConversations,
  CometChatMessageHeader,
  CometChatMessageList,
  CometChatMessageComposer,
} from "@cometchat/chat-uikit-react";

function ChatApp() {
  const [user, setUser] = useState<CometChat.User | undefined>();
  const [group, setGroup] = useState<CometChat.Group | undefined>();

  const handleConversationClick = (conversation: CometChat.Conversation) => {
    const entity = conversation.getConversationWith();
    if (conversation.getConversationType() === "user") {
      setUser(entity as CometChat.User);
      setGroup(undefined);
    } else {
      setGroup(entity as CometChat.Group);
      setUser(undefined);
    }
  };

  return (
    <div style={{ display: "flex", height: "100vh" }}>
      <div style={{ width: 360 }}>
        <CometChatConversations onItemClick={handleConversationClick} />
      </div>
      <div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
        <CometChatMessageHeader user={user} group={group} />
        <CometChatMessageList user={user} group={group} />
        <CometChatMessageComposer user={user} group={group} />
      </div>
    </div>
  );
}
```

***

## Filtering

Pass a `CometChat.ConversationsRequestBuilder` to `conversationsRequestBuilder` to control which conversations load. Pass the builder instance — not the result of `.build()`. Refer to [ConversationsRequestBuilder](/sdk/javascript/retrieve-conversations) for the full builder API.

```tsx theme={null}
<CometChatConversations
  conversationsRequestBuilder={
    new CometChat.ConversationsRequestBuilder()
      .setLimit(15)
      .setConversationType("user")
  }
/>
```

### Search

The component includes a built-in search bar. When the user types, it filters conversations client-side by name. For server-side search, pass a `searchRequestBuilder`:

```tsx theme={null}
<CometChatConversations
  searchRequestBuilder={
    new CometChat.ConversationsRequestBuilder().setLimit(30)
  }
/>
```

To use the search bar as a trigger for a custom search UI (like `CometChatSearch`), pass `onSearchBarClicked`:

```tsx theme={null}
<CometChatConversations
  onSearchBarClicked={() => openGlobalSearch()}
/>
```

### Filter Recipes

| Recipe            | Code                                                                       |
| ----------------- | -------------------------------------------------------------------------- |
| Only 1-on-1 chats | `new CometChat.ConversationsRequestBuilder().setConversationType("user")`  |
| Only group chats  | `new CometChat.ConversationsRequestBuilder().setConversationType("group")` |
| Limit page size   | `new CometChat.ConversationsRequestBuilder().setLimit(10)`                 |
| With tags         | `new CometChat.ConversationsRequestBuilder().setTags(["support"])`         |

***

## Actions and Events

### Callback Props

| Prop                 | Signature                                                           | Fires when                                        |
| -------------------- | ------------------------------------------------------------------- | ------------------------------------------------- |
| `onItemClick`        | `(conversation: CometChat.Conversation) => void`                    | User clicks a conversation item                   |
| `onSelect`           | `(conversation: CometChat.Conversation, selected: boolean) => void` | Conversation selected/deselected (selection mode) |
| `onError`            | `((error: CometChat.CometChatException) => void) \| null`           | SDK error occurs                                  |
| `onEmpty`            | `() => void`                                                        | List is empty after initial fetch                 |
| `onSearchBarClicked` | `() => void`                                                        | Search bar is clicked (makes input read-only)     |

### Events Emitted

UI events this component publishes:

| Event                     | Payload            | Fires when                  |
| ------------------------- | ------------------ | --------------------------- |
| `ui:conversation/deleted` | `{ conversation }` | User deletes a conversation |

### Events Received

UI events this component subscribes to (published by other components):

| Event                      | Payload                        | Behavior                                                             |
| -------------------------- | ------------------------------ | -------------------------------------------------------------------- |
| `ui:message/sent`          | `{ message, status }`          | Moves conversation to top, updates last message, resets unread count |
| `ui:compose/edit`          | `{ message, status }`          | Updates the conversation's last message                              |
| `ui:message/deleted`       | `{ message }`                  | Updates the conversation's last message                              |
| `ui:message/read`          | `{ message }`                  | Resets unread count for that conversation                            |
| `ui:conversation/updated`  | `{ conversation }`             | Updates the conversation in the list                                 |
| `ui:conversation/read`     | `{ conversationId }`           | Resets unread count by conversation ID                               |
| `ui:conversation/deleted`  | `{ conversation }`             | Removes the conversation from the list                               |
| `ui:group/created`         | `{ group }`                    | Adds the new group conversation to the list                          |
| `ui:group/deleted`         | `{ group }`                    | Removes the group conversation from the list                         |
| `ui:group/left`            | `{ group }`                    | Removes the group conversation from the list                         |
| `ui:group/member-added`    | `{ group, members, messages }` | Updates last message and moves to top                                |
| `ui:group/member-kicked`   | `{ group, member, message }`   | Updates last message and moves to top                                |
| `ui:group/member-banned`   | `{ group, member, message }`   | Updates last message and moves to top                                |
| `ui:group/member-unbanned` | `{ group, member, message }`   | Updates last message and moves to top                                |

### SDK Listeners (Automatic)

These SDK listeners are attached internally. The component updates its state automatically — no manual subscription needed:

* Message listeners: `onTextMessageReceived`, `onMediaMessageReceived`, `onCustomMessageReceived`, `onInteractiveMessageReceived`
* Typing: `onTypingStarted`, `onTypingEnded`
* Receipts: `onMessagesDelivered`, `onMessagesRead`
* Presence: `onUserOnline`, `onUserOffline`
* Groups: `onGroupMemberJoined`, `onGroupMemberLeft`, `onGroupMemberKicked`, `onGroupMemberBanned`, `onMemberAddedToGroup`

***

## Customization

### View Props

Use view props to replace sections of the default UI while keeping the component's behavior intact:

```tsx theme={null}
<CometChatConversations
  headerView={<MyCustomHeader />}
  itemView={(conversation) => <MyCustomItem conversation={conversation} />}
  emptyView={<EmptyState />}
  loadingView={<Skeleton />}
  errorView={<ErrorBanner />}
/>
```

| Slot           | Signature                     | Replaces                 |
| -------------- | ----------------------------- | ------------------------ |
| `itemView`     | `(conversation) => ReactNode` | Entire conversation row  |
| `leadingView`  | `(conversation) => ReactNode` | Avatar section           |
| `titleView`    | `(conversation) => ReactNode` | Conversation name        |
| `subtitleView` | `(conversation) => ReactNode` | Last message preview     |
| `trailingView` | `(conversation) => ReactNode` | Timestamp + unread badge |
| `headerView`   | `ReactNode`                   | Header area              |
| `searchView`   | `ReactNode`                   | Search bar               |
| `loadingView`  | `ReactNode`                   | Loading shimmer          |
| `emptyView`    | `ReactNode`                   | Empty state              |
| `errorView`    | `ReactNode`                   | Error state              |

#### itemView

Replace the entire list item row.

Default:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/Xgdtn9VZPDi47bm-/images/264a5cc0-list_item_view_default_web_screens-981f3ae54a9cef1c1f774bbda2f05a81.png?fit=max&auto=format&n=Xgdtn9VZPDi47bm-&q=85&s=ed5356973b0db36ca64693cc8949372d" width="1282" height="802" data-path="images/264a5cc0-list_item_view_default_web_screens-981f3ae54a9cef1c1f774bbda2f05a81.png" />
</Frame>

Customized:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/Xgdtn9VZPDi47bm-/images/288ed9bb-list_item_view_custom_web_screens-84bd7def72c71696e4ecb34d0ace5341.png?fit=max&auto=format&n=Xgdtn9VZPDi47bm-&q=85&s=41b94e842e6f7c747a13828428292a6a" width="1282" height="806" data-path="images/288ed9bb-list_item_view_custom_web_screens-84bd7def72c71696e4ecb34d0ace5341.png" />
</Frame>

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import { CometChat } from "@cometchat/chat-sdk-javascript";
    import {
      CometChatConversations,
      CometChatAvatar,
      CometChatDate,
    } from "@cometchat/chat-uikit-react";

    function CustomItemViewConversations() {
      const getItemView = (conversation: CometChat.Conversation) => {
        const title = conversation.getConversationWith().getName();
        const timestamp = conversation?.getLastMessage()?.getSentAt();

        return (
          <div className="conversations__custom-item">
            <CometChatAvatar.Root name={title}>
              <CometChatAvatar.Image />
              <CometChatAvatar.Initials />
            </CometChatAvatar.Root>
            <span className="conversations__custom-item-title">{title}</span>
            {timestamp ? (
              <CometChatDate.Root timestamp={timestamp}>
                <CometChatDate.Text />
              </CometChatDate.Root>
            ) : null}
          </div>
        );
      };

      return <CometChatConversations itemView={getItemView} />;
    }
    ```
  </Tab>

  <Tab title="CSS">
    ```css theme={null}
    .conversations__custom-item {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 8px 16px;
      width: 100%;
    }

    .conversations__custom-item-title {
      flex: 1;
      font: 500 16px/19.2px Roboto;
      color: #141414;
    }

    .cometchat-conversations .cometchat-avatar {
      border-radius: 8px;
      width: 32px;
      height: 32px;
    }
    ```
  </Tab>
</Tabs>

#### leadingView

Replace the avatar / left section. Typing-aware avatar example.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/XgQ9DxAoWn0btB5m/images/5f55a4a0-conversations_leadingview-3b297f3151794854485fc087d0c0aeec.png?fit=max&auto=format&n=XgQ9DxAoWn0btB5m&q=85&s=0f2dcf0ce92e9d18a5fe0494c5a15da3" width="1280" height="800" data-path="images/5f55a4a0-conversations_leadingview-3b297f3151794854485fc087d0c0aeec.png" />
</Frame>

```tsx theme={null}
import { useEffect, useRef, useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
  CometChatConversations,
  CometChatAvatar,
  useLoggedInUser,
} from "@cometchat/chat-uikit-react";

function TypingAwareConversations() {
  const [isTyping, setIsTyping] = useState(false);
  const typingObjRef = useRef<CometChat.TypingIndicator | null>(null);
  const loggedInUser = useLoggedInUser();

  useEffect(() => {
    const listenerId = "typing_demo_" + Date.now();
    CometChat.addMessageListener(
      listenerId,
      new CometChat.MessageListener({
        onTypingStarted: (typingIndicator: CometChat.TypingIndicator) => {
          typingObjRef.current = typingIndicator;
          setIsTyping(true);
        },
        onTypingEnded: (typingIndicator: CometChat.TypingIndicator) => {
          if (
            typingObjRef.current &&
            typingObjRef.current.getSender().getUid() ===
              typingIndicator.getSender().getUid()
          ) {
            typingObjRef.current = null;
            setIsTyping(false);
          }
        },
      })
    );
    return () => {
      CometChat.removeMessageListener(listenerId);
    };
  }, []);

  const getLeadingView = (conversation: CometChat.Conversation) => {
    const entity = conversation.getConversationWith();
    const isUser = entity instanceof CometChat.User;
    const isGroup = entity instanceof CometChat.Group;

    const isMyTyping = isUser
      ? (entity as CometChat.User).getUid() ===
          typingObjRef.current?.getSender().getUid() &&
        loggedInUser?.getUid() === typingObjRef.current?.getReceiverId()
      : isGroup &&
        (entity as CometChat.Group).getGuid() ===
          typingObjRef.current?.getReceiverId();

    const avatar = isUser
      ? (entity as CometChat.User).getAvatar()
      : (entity as CometChat.Group).getIcon();

    return (
      <div className="conversations__leading-view">
        <CometChatAvatar.Root
          image={isTyping && isMyTyping ? undefined : avatar}
          name={isTyping && isMyTyping ? undefined : entity.getName()}
        >
          <CometChatAvatar.Image />
          <CometChatAvatar.Initials />
        </CometChatAvatar.Root>
      </div>
    );
  };

  return <CometChatConversations leadingView={getLeadingView} />;
}
```

#### titleView

Replace the name / title text. Inline user status example.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/7a4hqm7gLVRmX34O/images/015d947c-conversations_titleview-b5822bb42232ef47727b553cbf1facd8.png?fit=max&auto=format&n=7a4hqm7gLVRmX34O&q=85&s=2b958506b652b8796c372c5300304a46" width="1280" height="800" data-path="images/015d947c-conversations_titleview-b5822bb42232ef47727b553cbf1facd8.png" />
</Frame>

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import { CometChat } from "@cometchat/chat-sdk-javascript";
    import { CometChatConversations } from "@cometchat/chat-uikit-react";

    function StatusTitleConversations() {
      const getTitleView = (conversation: CometChat.Conversation) => {
        const user =
          conversation.getConversationType() === "user"
            ? (conversation.getConversationWith() as CometChat.User)
            : undefined;

        return (
          <div className="conversations__title-view">
            <span className="conversations__title-view-name">
              {user
                ? conversation.getConversationWith().getName() + " · "
                : conversation.getConversationWith().getName()}
            </span>
            {user && (
              <span className="conversations__title-view-status">
                {user.getStatusMessage()}
              </span>
            )}
          </div>
        );
      };

      return <CometChatConversations titleView={getTitleView} />;
    }
    ```
  </Tab>

  <Tab title="CSS">
    ```css theme={null}
    .cometchat-conversations .conversations__title-view {
      display: flex;
      gap: 4px;
      width: 100%;
    }

    .conversations__title-view-name {
      color: #141414;
      font: 500 16px/19.2px Roboto;
    }

    .conversations__title-view-status {
      color: #6852d6;
      font: 400 16px/19.2px Roboto;
    }
    ```
  </Tab>
</Tabs>

#### subtitleView

Replace the last message preview text.

Default:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/mq8rEbFfi0JjKmkM/images/68f87420-subtitle_View_default_web_screens-981f3ae54a9cef1c1f774bbda2f05a81.png?fit=max&auto=format&n=mq8rEbFfi0JjKmkM&q=85&s=f4b9024c0fe36fea8b75bfbb710829d4" width="1282" height="802" data-path="images/68f87420-subtitle_View_default_web_screens-981f3ae54a9cef1c1f774bbda2f05a81.png" />
</Frame>

Customized:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/jpEUuHUk-hvu4tQT/images/a5a0ef3f-subtitle_View_custom_web_screens-cc38fdf73a8f272804d2c3b73e898ce5.png?fit=max&auto=format&n=jpEUuHUk-hvu4tQT&q=85&s=4023eda0cac95be41305ce55674796a8" width="1282" height="806" data-path="images/a5a0ef3f-subtitle_View_custom_web_screens-cc38fdf73a8f272804d2c3b73e898ce5.png" />
</Frame>

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import { CometChat } from "@cometchat/chat-sdk-javascript";
    import { CometChatConversations } from "@cometchat/chat-uikit-react";

    function formatTimestamp(timestamp: number): string {
      return new Date(timestamp * 1000).toLocaleString();
    }

    function SubtitleConversations() {
      const getSubtitleView = (conversation: CometChat.Conversation) => {
        if (conversation.getConversationType() === "user") {
          return (
            <span className='custom-conversation-subtitle'>
              Last active:{" "}
              {new Date(
                (conversation.getConversationWith() as CometChat.User).getLastActiveAt() * 1000
              ).toLocaleString()}
            </span>
          );
        }
        return (
          <span className='custom-conversation-subtitle'>
            Created:{" "}
            {new Date(
              (conversation.getConversationWith() as CometChat.Group).getCreatedAt() * 1000
            ).toLocaleString()}
          </span>
        );
      };

      return <CometChatConversations subtitleView={getSubtitleView} />;
    }
    ```
  </Tab>

  <Tab title="CSS">
    ```css theme={null}
    .custom-conversation-subtitle {
      overflow: hidden;
      color: grey;
      text-overflow: ellipsis;
      white-space: nowrap;
      font: var(--cometchat-font-body-regular);
    }
    ```
  </Tab>
</Tabs>

#### trailingView

Replace the timestamp / badge / right section. Relative time badge example.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/PrOf0fpV33FkfOMB/images/13a712d0-conversations_trailingview-3aecd22196f2ccfb66af2b9a00d2c93f.png?fit=max&auto=format&n=PrOf0fpV33FkfOMB&q=85&s=8dba0b927de0e2fdd7aa1bcb41020611" width="1280" height="800" data-path="images/13a712d0-conversations_trailingview-3aecd22196f2ccfb66af2b9a00d2c93f.png" />
</Frame>

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import { CometChat } from "@cometchat/chat-sdk-javascript";
    import { CometChatConversations } from "@cometchat/chat-uikit-react";

    function RelativeTimeConversations() {
      const getTrailingView = (conv: CometChat.Conversation) => {
        if (!conv.getLastMessage()) return <></>;

        const timestamp = conv.getLastMessage()?.getSentAt() * 1000;
        const now = Date.now();
        const diffInMinutes = Math.floor((now - timestamp) / (1000 * 60));
        const diffInHours = Math.floor((now - timestamp) / (1000 * 60 * 60));

        let className = "conversations__trailing-view-min";
        let topLabel = `${diffInMinutes}`;
        let bottomLabel = diffInMinutes === 1 ? "Min ago" : "Mins ago";

        if (diffInHours >= 1 && diffInHours <= 10) {
          className = "conversations__trailing-view-hour";
          topLabel = `${diffInHours}`;
          bottomLabel = diffInHours === 1 ? "Hour ago" : "Hours ago";
        } else if (diffInHours > 10) {
          className = "conversations__trailing-view-date";
          const time = new Date(timestamp);
          topLabel = time.toLocaleDateString("en-US", { day: "numeric" });
          bottomLabel = time.toLocaleDateString("en-US", { month: "short", year: "numeric" });
        }

        return (
          <div className={`conversations__trailing-view ${className}`}>
            <span className="conversations__trailing-view-time">{topLabel}</span>
            <span className="conversations__trailing-view-status">{bottomLabel}</span>
          </div>
        );
      };

      return <CometChatConversations trailingView={getTrailingView} />;
    }
    ```
  </Tab>

  <Tab title="CSS">
    ```css theme={null}
    .conversations__trailing-view {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 55px;
      height: 40px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .conversations__trailing-view-min { background-color: #e0d4f7; }
    .conversations__trailing-view-hour { background-color: #fff3cd; }
    .conversations__trailing-view-date { background-color: #f8d7da; }

    .conversations__trailing-view-time {
      font: 600 18px Roboto;
      color: #4a3f99;
      margin-bottom: 4px;
    }

    .conversations__trailing-view-status {
      font: 600 8px Roboto;
      color: #6a5b99;
    }

    .cometchat-conversations .cometchat-list-item__trailing-view {
      height: 50px;
    }
    ```
  </Tab>
</Tabs>

#### headerView

Replace the entire header bar.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/G6Puyz_3Zlaowa9R/images/c8e9953f-conversations_headerview-334738e0afe495ef89165ee0cea86b5c.png?fit=max&auto=format&n=G6Puyz_3Zlaowa9R&q=85&s=3127a11dab630e79854eacb696685993" width="1282" height="414" data-path="images/c8e9953f-conversations_headerview-334738e0afe495ef89165ee0cea86b5c.png" />
</Frame>

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import {
      CometChatButton,
      CometChatConversations,
      useLocale,
    } from "@cometchat/chat-uikit-react";

    function CustomHeaderConversations() {
      const { getLocalizedString } = useLocale();

      return (
        <CometChatConversations
          headerView={
            <div className="conversations__header">
              <div className="conversations__header__title">
                {getLocalizedString("chats")}
              </div>
              <CometChatButton.Root onClick={() => { /* handle click */ }}>
                <CometChatButton.Icon />
              </CometChatButton.Root>
            </div>
          }
        />
      );
    }
    ```
  </Tab>

  <Tab title="CSS">
    ```css theme={null}
    .conversations__header {
      display: flex;
      width: 100%;
      padding: 8px 16px;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      border-radius: 10px;
      border: 1px solid #e8e8e8;
      background: #edeafa;
    }

    .conversations__header__title {
      overflow: hidden;
      color: #141414;
      text-overflow: ellipsis;
      font: 700 24px Roboto;
    }

    .conversations__header .cometchat-button .cometchat-button__icon {
      background: #141414;
    }

    .conversations__header .cometchat-button {
      width: 24px;
      border: none;
      background: transparent;
      border-radius: 0;
    }
    ```
  </Tab>
</Tabs>

#### options

Replace the context menu / hover actions on each conversation item.

Default:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/G6Puyz_3Zlaowa9R/images/c75bf066-options_default_web_screens-504fece998247b272a5ba5ca5d2f6678.png?fit=max&auto=format&n=G6Puyz_3Zlaowa9R&q=85&s=8816bde7bc69f022aaf8527cb6391d90" width="1282" height="833" data-path="images/c75bf066-options_default_web_screens-504fece998247b272a5ba5ca5d2f6678.png" />
</Frame>

Customized:

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/ugckbRl5Q-H7t8X2/images/e089983a-options_custom_web_screens-7996ecee34fa203d7bc68bd45ab1a875.png?fit=max&auto=format&n=ugckbRl5Q-H7t8X2&q=85&s=019bf98e47d1c9385c4cd74ddcdd9657" width="1282" height="833" data-path="images/e089983a-options_custom_web_screens-7996ecee34fa203d7bc68bd45ab1a875.png" />
</Frame>

<Tabs>
  <Tab title="TypeScript">
    ```tsx theme={null}
    import { CometChat } from "@cometchat/chat-sdk-javascript";
    import {
      CometChatConversations,
      type CometChatConversationOption,
    } from "@cometchat/chat-uikit-react";

    function CustomOptionsConversations() {
      const getOptions = (conversation: CometChat.Conversation): CometChatConversationOption[] => [
        {
          id: "delete",
          title: "Delete",
          onClick: (conv) => { /* delete logic */ },
        },
        {
          id: "mute",
          title: "Mute Notification",
          onClick: (conv) => { /* mute logic */ },
        },
        {
          id: "unread",
          title: "Mark as Unread",
          onClick: (conv) => { /* mark unread logic */ },
        },
        {
          id: "block",
          title: "Block",
          onClick: (conv) => { /* block logic */ },
        },
      ];

      return <CometChatConversations options={getOptions} />;
    }
    ```
  </Tab>

  <Tab title="CSS">
    ```css theme={null}
    .cometchat-conversations .cometchat-menu-list__main-menu-item-icon-delete {
      background: red;
    }

    .cometchat-conversations .cometchat-menu-list__sub-menu {
      background: transparent;
      box-shadow: none;
    }
    ```
  </Tab>
</Tabs>

### Compound Composition

For full layout control, use sub-components. Omit any sub-component to hide it:

```tsx theme={null}
<CometChatConversations.Root onItemClick={handleClick}>
  {/* No Header or SearchBar — they won't render */}
  <CometChatConversations.List />
</CometChatConversations.Root>
```

Available sub-components:

| Sub-component  | Description                    | Props                                                                   | Flat API equivalent |
| -------------- | ------------------------------ | ----------------------------------------------------------------------- | ------------------- |
| `Root`         | Context provider and container | All Root props + `children`                                             | —                   |
| `List`         | Scrollable conversation list   | `itemView`, `className`                                                 | `itemView`          |
| `Item`         | Individual conversation row    | `leadingView`, `titleView`, `subtitleView`, `trailingView`, `className` | Per-item view props |
| `Header`       | Header area                    | `title`, `children`                                                     | `headerView`        |
| `SearchBar`    | Search input                   | `placeholder`, `onClick`                                                | `searchView`        |
| `EmptyState`   | Empty state                    | `children`                                                              | `emptyView`         |
| `ErrorState`   | Error state                    | `children`                                                              | `errorView`         |
| `LoadingState` | Loading shimmer                | `children`                                                              | `loadingView`       |

### CSS Styling

Override design tokens on the component selector:

```css theme={null}
.cometchat-conversations {
  --cometchat-background-color-01: #1a1a2e;
  --cometchat-text-color-primary: #ffffff;
}

.cometchat-conversations__item--active {
  background: var(--cometchat-primary-color);
}
```

***

## Props

All props are optional.

<Note>
  View slot props (`headerView`, `searchView`, `loadingView`, `emptyView`, `errorView`, `itemView`, `leadingView`, `titleView`, `subtitleView`, `trailingView`) are convenience props available only on the flat API. In compound composition mode, use the corresponding sub-components directly.
</Note>

***

### conversationsRequestBuilder

Custom request builder for fetching conversations. Controls pagination, filtering, and sorting.

|         |                                         |
| ------- | --------------------------------------- |
| Type    | `CometChat.ConversationsRequestBuilder` |
| Default | SDK default (limit 30)                  |

***

### searchRequestBuilder

Custom request builder used specifically when the user searches. Separate from the main builder.

|         |                                         |
| ------- | --------------------------------------- |
| Type    | `CometChat.ConversationsRequestBuilder` |
| Default | `undefined`                             |

***

### searchKeyword

Initial search keyword to pre-filter conversations on mount.

|         |             |
| ------- | ----------- |
| Type    | `string`    |
| Default | `undefined` |

***

### activeConversation

The currently active/highlighted conversation. The matching item receives an active visual state.

|         |                          |
| ------- | ------------------------ |
| Type    | `CometChat.Conversation` |
| Default | `undefined`              |

***

### lastMessageDateTimeFormat

Custom date/time format for the last message timestamp shown in each conversation item.

|         |                                                                                           |
| ------- | ----------------------------------------------------------------------------------------- |
| Type    | `CometChatDateFormatConfig`                                                               |
| Default | `{ today: 'hh:mm A', yesterday: 'Yesterday', lastWeek: 'dddd', otherDays: 'DD/MM/YYYY' }` |

***

### hideReceipts

Hide message delivery/read receipts (double ticks) on conversation items.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideUserStatus

Hide the online/offline status indicator on user avatars.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideGroupType

Hide the group type indicator (public/private/password) on group conversation items.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideUnreadCount

Hide the unread message count badge.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideDeleteConversation

Hide the delete option in the conversation item's context menu.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### showSearchBar

Whether to show the search bar. Set to `false` to hide it entirely.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `true`    |

***

### showScrollbar

Show the native scrollbar on the conversation list.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### selectionMode

Enable selection mode for multi-select operations.

|         |                                    |
| ------- | ---------------------------------- |
| Type    | `'none' \| 'single' \| 'multiple'` |
| Default | `'none'`                           |

***

### disableSoundForMessages

Disable the notification sound when new messages arrive.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### customSoundForMessages

Custom sound URL to play when new messages arrive (replaces the built-in sound).

|         |                             |
| ------- | --------------------------- |
| Type    | `string`                    |
| Default | Built-in notification sound |

***

### options

Function that returns context menu options for each conversation item (shown on hover/swipe).

|         |                                                                           |
| ------- | ------------------------------------------------------------------------- |
| Type    | `(conversation: CometChat.Conversation) => CometChatConversationOption[]` |
| Default | Default options (delete)                                                  |

```tsx theme={null}
<CometChatConversations
  options={(conversation) => [
    {
      id: "pin",
      title: "Pin",
      iconURL: pinIcon,
      onClick: (conv) => pinConversation(conv),
    },
    {
      id: "mute",
      title: "Mute",
      iconURL: muteIcon,
      onClick: (conv) => muteConversation(conv),
    },
  ]}
/>
```

***

### onItemClick

Callback when a conversation item is clicked.

|         |                                                  |
| ------- | ------------------------------------------------ |
| Type    | `(conversation: CometChat.Conversation) => void` |
| Default | `undefined`                                      |

***

### onSelect

Callback when a conversation is selected or deselected (only fires in selection mode).

|         |                                                                     |
| ------- | ------------------------------------------------------------------- |
| Type    | `(conversation: CometChat.Conversation, selected: boolean) => void` |
| Default | `undefined`                                                         |

***

### onError

Callback when an SDK error occurs during fetch or real-time operations.

|         |                                                           |
| ------- | --------------------------------------------------------- |
| Type    | `((error: CometChat.CometChatException) => void) \| null` |
| Default | `null`                                                    |

***

### onEmpty

Callback when the conversation list is empty after the initial fetch completes.

|         |              |
| ------- | ------------ |
| Type    | `() => void` |
| Default | `undefined`  |

***

### onSearchBarClicked

Callback when the search bar is clicked. When provided, the search input becomes read-only and acts as a trigger (useful for opening a global search component like `CometChatSearch`).

|         |              |
| ------- | ------------ |
| Type    | `() => void` |
| Default | `undefined`  |

***

## CSS Architecture

The component uses CSS custom properties (design tokens) that are bundled with `@cometchat/chat-uikit-react`. The cascade:

1. Global tokens (e.g., `--cometchat-primary-color`, `--cometchat-background-color-01`) are set on the `.cometchat` root wrapper.
2. Component CSS (`.cometchat-conversations`) consumes these tokens via `var()` with fallback values.
3. Overrides target `.cometchat-conversations` descendant selectors in a global stylesheet.

To scope overrides to a single instance when multiple `CometChatConversations` exist on the same page, wrap the component in a container and scope selectors:

```css theme={null}
.sidebar-left .cometchat-conversations .cometchat-badge {
  background: #e5484d;
}
```

Overrides survive component updates because the component never sets inline styles on these elements — all styling flows through CSS classes and custom properties.

### Key Selectors

| Target           | Selector                                                           |
| ---------------- | ------------------------------------------------------------------ |
| Root             | `.cometchat-conversations`                                         |
| Header title     | `.cometchat-conversations .cometchat-list__header-title`           |
| List item        | `.cometchat-conversations .cometchat-list-item`                    |
| Body title       | `.cometchat-conversations .cometchat-list-item__body-title`        |
| Avatar           | `.cometchat-conversations .cometchat-avatar`                       |
| Avatar text      | `.cometchat-conversations .cometchat-avatar__text`                 |
| Unread badge     | `.cometchat-conversations .cometchat-badge`                        |
| Subtitle text    | `.cometchat-conversations .cometchat-conversations__subtitle-text` |
| Status indicator | `.cometchat-conversations .cometchat-status-indicator`             |
| Read receipts    | `.cometchat-conversations .cometchat-receipts-read`                |
| Active item      | `.cometchat-conversations__list-item-active .cometchat-list-item`  |
| Typing indicator | `.cometchat-conversations__subtitle-typing`                        |
| Trailing view    | `.cometchat-conversations__trailing-view`                          |

### Example: Brand-themed conversations

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-rn-guide-message-privately/_MYSdWhXnUkTkjEH/images/46655ced-style_custom_web_screens-967e2c7c42b5c97c59c10a9212aef0c4.png?fit=max&auto=format&n=_MYSdWhXnUkTkjEH&q=85&s=9176b9c41b568adf302f3eb2d1338d88" width="1282" height="802" data-path="images/46655ced-style_custom_web_screens-967e2c7c42b5c97c59c10a9212aef0c4.png" />
</Frame>

```css theme={null}
.cometchat-conversations .cometchat-conversations__item-title,
.cometchat-conversations .cometchat-conversations__header-title,
.cometchat-conversations .cometchat-avatar__text,
.cometchat-conversations .cometchat-conversations__item-unread-badge,
.cometchat-conversations .cometchat-conversations__item-subtitle-text {
  font-family: "SF Pro";
}

.cometchat-conversations .cometchat-conversations__header {
  background: #fef8f8;
  border-bottom: 2px solid #f4b6b8;
}

.cometchat-conversations .cometchat-avatar {
  background: #FAAA75;
}

.cometchat-conversations .cometchat-status-indicator {
  min-width: 10px;
  height: 10px;
}

.cometchat-conversations .cometchat-conversations__item-unread-badge {
  background: #F76809;
}

.cometchat-conversations .cometchat-conversations__item-receipt--read {
  background: #FAAA75;
}
```

### Customization Matrix

| What to change                        | Where           | Property/API                            | Example                                                                                  |
| ------------------------------------- | --------------- | --------------------------------------- | ---------------------------------------------------------------------------------------- |
| Override behavior on user interaction | Component props | `on<Event>` callbacks                   | `onItemClick={(c) => setActive(c)}`                                                      |
| Filter which conversations appear     | Component props | `conversationsRequestBuilder`           | `conversationsRequestBuilder={new CometChat.ConversationsRequestBuilder().setLimit(10)}` |
| Toggle visibility of UI elements      | Component props | `hide<Feature>` boolean props           | `hideReceipts={true}`                                                                    |
| Replace a section of the list item    | Component props | `<slot>View` render props               | `itemView={(conversation) => <div>...</div>}`                                            |
| Change colors, fonts, spacing         | Global CSS      | Target `.cometchat-conversations` class | `.cometchat-conversations .cometchat-badge { background: #e5484d; }`                     |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Users" icon="user" href="/ui-kit/react/components/users">
    Browse and select users for new conversations
  </Card>

  <Card title="Message List" icon="comments" href="/ui-kit/react/components/message-list">
    Display messages for the selected conversation
  </Card>

  <Card title="Search" icon="magnifying-glass" href="/ui-kit/react/components/search">
    Search across conversations and messages
  </Card>

  <Card title="Theming" icon="paintbrush" href="/ui-kit/react/theming">
    Customize colors, fonts, and spacing
  </Card>
</CardGroup>
