Skip to main content
The CometChatConversations component displays a list of all conversations (one-on-one and group chats) for the currently logged-in user. It shows the last message, unread count, typing indicators, and user presence in real-time.
{
  "component": "CometChatConversations",
  "package": "CometChatUIKitSwift",
  "import": "import CometChatUIKitSwift\nimport CometChatSDK",
  "description": "Displays a list of all conversations for the logged-in user with real-time updates for messages, typing indicators, and presence.",
  "inherits": "UIViewController",
  "primaryOutput": {
    "callback": "onItemClick",
    "type": "(Conversation, IndexPath) -> Void"
  },
  "props": {
    "data": {
      "conversationRequestBuilder": {
        "type": "ConversationRequest.ConversationRequestBuilder?",
        "default": "nil",
        "note": "Custom request builder for filtering conversations"
      }
    },
    "callbacks": {
      "onItemClick": "(Conversation, IndexPath) -> Void",
      "onItemLongClick": "(Conversation, IndexPath) -> Void",
      "onBack": "() -> Void",
      "onSelection": "([Conversation]) -> Void",
      "onError": "(CometChatException) -> Void",
      "onEmpty": "() -> Void",
      "onLoad": "([Conversation]) -> Void"
    },
    "visibility": {
      "hideSearch": { "type": "Bool", "default": false },
      "hideReceipts": { "type": "Bool", "default": false },
      "hideUserStatus": { "type": "Bool", "default": false },
      "hideGroupType": { "type": "Bool", "default": false },
      "hideDeleteConversationOption": { "type": "Bool", "default": false },
      "hideNavigationBar": { "type": "Bool", "default": false },
      "hideBackButton": { "type": "Bool", "default": false }
    },
    "sound": {
      "disableSoundForMessages": { "type": "Bool", "default": false },
      "customSoundForMessages": { "type": "URL?", "default": "nil" }
    },
    "selection": {
      "selectionMode": { "type": "SelectionMode", "default": ".none" }
    },
    "viewSlots": {
      "listItemView": "(Conversation) -> UIView",
      "leadingView": "(Conversation) -> UIView",
      "titleView": "(Conversation) -> UIView",
      "subtitleView": "(Conversation) -> UIView",
      "tailView": "(Conversation) -> UIView",
      "emptyStateView": "() -> UIView",
      "errorStateView": "() -> UIView",
      "loadingStateView": "() -> UIView"
    },
    "formatting": {
      "datePattern": "(Conversation) -> String",
      "textFormatters": "[CometChatTextFormatter]"
    }
  },
  "events": [
    {
      "name": "ccConversationDelete",
      "payload": "Conversation",
      "description": "Fires when a conversation is deleted"
    }
  ],
  "sdkListeners": [
    "onMessageReceived",
    "onMessageEdited",
    "onMessageDeleted",
    "onTypingStarted",
    "onTypingEnded",
    "onUserOnline",
    "onUserOffline",
    "onGroupMemberJoined",
    "onGroupMemberLeft"
  ],
  "compositionExample": {
    "description": "Conversations list navigating to Messages",
    "components": ["CometChatConversations", "CometChatMessages"],
    "flow": "User taps conversation → onItemClick fires → Navigate to CometChatMessages with user/group"
  },
  "types": {
    "Conversation": {
      "conversationId": "String?",
      "conversationType": "ConversationType",
      "conversationWith": "AppEntity?",
      "lastMessage": "BaseMessage?",
      "unreadMessageCount": "Int"
    },
    "ConversationType": {
      "user": "One-on-one conversation",
      "group": "Group conversation",
      "both": "All conversation types"
    }
  }
}

Where It Fits

CometChatConversations serves as the main entry point for chat functionality. It displays all conversations and navigates to CometChatMessages when a conversation is selected.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class ChatListViewController: UIViewController {
    
    private var conversationsController: CometChatConversations!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupConversations()
    }
    
    private func setupConversations() {
        conversationsController = CometChatConversations()
        
        // Handle conversation selection - navigate to messages
        conversationsController.set(onItemClick: { [weak self] conversation, indexPath in
            self?.openMessages(for: conversation)
        })
        
        navigationController?.pushViewController(conversationsController, animated: true)
    }
    
    private func openMessages(for conversation: Conversation) {
        let messagesVC = CometChatMessages()
        
        if let user = conversation.conversationWith as? User {
            messagesVC.set(user: user)
        } else if let group = conversation.conversationWith as? Group {
            messagesVC.set(group: group)
        }
        
        navigationController?.pushViewController(messagesVC, animated: true)
    }
}

Minimal Render

import CometChatUIKitSwift

let conversations = CometChatConversations()
navigationController?.pushViewController(conversations, animated: true)

Filtering

Use ConversationRequest.ConversationRequestBuilder to filter which conversations appear in the list. The builder pattern allows chaining multiple filter conditions.
import CometChatUIKitSwift
import CometChatSDK

// Create a custom request builder
let requestBuilder = ConversationRequest.ConversationRequestBuilder(limit: 30)
    .set(conversationType: .both)

let conversations = CometChatConversations(conversationRequestBuilder: requestBuilder)

Filter Recipes

RecipeCode
Show only one-on-one chats.set(conversationType: .user)
Show only group chats.set(conversationType: .group)
Filter by tags.withTags(true).set(tags: ["support", "sales"])
Limit resultsConversationRequestBuilder(limit: 20)
Include user/group tags.withUserAndGroupTags(true)

Actions and Events

Callback Props

onItemClick

Fires when a user taps on a conversation. Use this to navigate to the messages screen.
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()

conversations.set(onItemClick: { [weak self] conversation, indexPath in
    guard let self = self else { return }
    
    let messagesVC = CometChatMessages()
    
    if let user = conversation.conversationWith as? User {
        messagesVC.set(user: user)
    } else if let group = conversation.conversationWith as? Group {
        messagesVC.set(group: group)
    }
    
    self.navigationController?.pushViewController(messagesVC, animated: true)
})

onItemLongClick

Fires when a user long-presses on a conversation. Use this to show additional options like delete or mute.
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()

conversations.set(onItemLongClick: { [weak self] conversation, indexPath in
    guard let self = self else { return }
    
    let alert = UIAlertController(title: "Options", message: nil, preferredStyle: .actionSheet)
    
    alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { [weak self] _ in
        self?.deleteConversation(conversation)
    })
    
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    self.present(alert, animated: true)
})

// Helper method to delete conversation using SDK
private func deleteConversation(_ conversation: Conversation) {
    CometChat.deleteConversation(
        conversationWith: conversation.conversationWith?.uid ?? "",
        conversationType: conversation.conversationType
    ) { success in
        print("Conversation deleted successfully")
    } onError: { error in
        print("Delete failed: \(error?.errorDescription ?? "")")
    }
}

onBack

Fires when the back button is pressed. Use this for custom navigation handling.
import CometChatUIKitSwift

let conversations = CometChatConversations()

conversations.set(onBack: { [weak self] in
    self?.navigationController?.popViewController(animated: true)
})

onSelection

Fires when conversations are selected in selection mode. Returns the list of selected conversations.
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()
conversations.selectionMode = .multiple

conversations.set(onSelection: { [weak self] selectedConversations in
    print("Selected \(selectedConversations.count) conversations")
})

onError

Fires when an error occurs while loading conversations.
import CometChatUIKitSwift

let conversations = CometChatConversations()

conversations.set(onError: { error in
    print("Error loading conversations: \(error.errorDescription)")
})

onEmpty

Fires when the conversation list is empty.
import CometChatUIKitSwift

let conversations = CometChatConversations()

conversations.set(onEmpty: {
    print("No conversations found")
})

onLoad

Fires when conversations are successfully loaded.
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()

conversations.set(onLoad: { conversations in
    print("Loaded \(conversations.count) conversations")
})

Actions Reference

MethodDescriptionExample
set(onItemClick:)Triggered when a conversation is tappedNavigate to messages
set(onItemLongClick:)Triggered on long pressShow options menu
set(onBack:)Triggered when back button is pressedCustom navigation
set(onSelection:)Triggered in selection modeMulti-select conversations
set(onError:)Triggered when an error occursShow error alert
set(onEmpty:)Triggered when list is emptyShow empty state
set(onLoad:)Triggered when conversations loadAnalytics tracking

Global UI Events

EventFires whenPayload
ccConversationDeleteA conversation is deletedConversation
import CometChatUIKitSwift
import CometChatSDK

class MyViewController: UIViewController, CometChatConversationEventListener {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CometChatConversationEvents.addListener("my-listener", self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        CometChatConversationEvents.removeListener("my-listener")
    }
    
    func ccConversationDelete(conversation: Conversation) {
        print("Conversation deleted: \(conversation.conversationId ?? "")")
    }
}

SDK Events (Real-Time, Automatic)

SDK ListenerInternal behavior
onMessageReceivedUpdates last message and moves conversation to top
onMessageEditedUpdates last message preview if edited message is latest
onMessageDeletedUpdates last message preview if deleted message was latest
onTypingStartedShows typing indicator for the conversation
onTypingEndedHides typing indicator for the conversation
onUserOnlineUpdates online status indicator for user conversations
onUserOfflineUpdates offline status indicator for user conversations
onGroupMemberJoinedUpdates group member count
onGroupMemberLeftUpdates group member count

Custom View Slots

SlotSignatureReplaces
listItemView(Conversation) -> UIViewEntire conversation row
leadingView(Conversation) -> UIViewAvatar / left section
titleView(Conversation) -> UIViewName / title text
subtitleView(Conversation) -> UIViewLast message preview
tailView(Conversation) -> UIViewRight side (time, badge)
emptyStateView() -> UIViewEmpty state display
errorStateView() -> UIViewError state display
loadingStateView() -> UIViewLoading state display

listItemView

Replace the entire conversation row with a custom design.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()

conversations.set(listItemView: { conversation in
    let customView = CustomConversationCell()
    customView.configure(with: conversation)
    return customView
})
// CustomConversationCell.swift
class CustomConversationCell: UIView {
    
    private let avatarView = CometChatAvatar(image: UIImage())
    private let nameLabel = UILabel()
    private let messageLabel = UILabel()
    private let timeLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupUI() {
        nameLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
        messageLabel.font = UIFont.systemFont(ofSize: 14)
        messageLabel.textColor = UIColor.secondaryLabel
        timeLabel.font = UIFont.systemFont(ofSize: 12)
        timeLabel.textColor = UIColor.tertiaryLabel
        
        // Add subviews and constraints...
    }
    
    func configure(with conversation: Conversation) {
        if let user = conversation.conversationWith as? User {
            nameLabel.text = user.name
            avatarView.setAvatar(avatarUrl: user.avatar, with: user.name ?? "")
        } else if let group = conversation.conversationWith as? Group {
            nameLabel.text = group.name
            avatarView.setAvatar(avatarUrl: group.icon, with: group.name ?? "")
        }
        
        if let textMessage = conversation.lastMessage as? TextMessage {
            messageLabel.text = textMessage.text
        }
    }
}

subtitleView

Customize just the subtitle area below the conversation name.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()

conversations.set(subtitleView: { conversation in
    let label = UILabel()
    label.font = UIFont.systemFont(ofSize: 13)
    label.textColor = UIColor.secondaryLabel
    
    if let textMessage = conversation.lastMessage as? TextMessage {
        label.text = textMessage.text
    } else if conversation.lastMessage is MediaMessage {
        label.text = "📷 Photo"
    } else {
        label.text = "No messages yet"
    }
    
    return label
})

tailView

Customize the right side of the conversation row (time, unread badge). Note: The setter method is set(trailView:).
import UIKit
import CometChatUIKitSwift
import CometChatSDK

let conversations = CometChatConversations()

conversations.set(trailView: { conversation in
    let stackView = UIStackView()
    stackView.axis = .vertical
    stackView.alignment = .trailing
    stackView.spacing = 4
    
    // Time label
    let timeLabel = UILabel()
    timeLabel.font = UIFont.systemFont(ofSize: 12)
    timeLabel.textColor = UIColor.tertiaryLabel
    
    if let sentAt = conversation.lastMessage?.sentAt {
        let date = Date(timeIntervalSince1970: TimeInterval(sentAt))
        let formatter = DateFormatter()
        formatter.dateFormat = "h:mm a"
        timeLabel.text = formatter.string(from: date)
    }
    
    stackView.addArrangedSubview(timeLabel)
    
    // Unread badge
    if conversation.unreadMessageCount > 0 {
        let badge = UILabel()
        badge.text = "\(conversation.unreadMessageCount)"
        badge.font = UIFont.systemFont(ofSize: 12, weight: .bold)
        badge.textColor = UIColor.white
        badge.backgroundColor = UIColor.systemRed
        badge.textAlignment = .center
        badge.layer.cornerRadius = 10
        badge.clipsToBounds = true
        badge.widthAnchor.constraint(greaterThanOrEqualToConstant: 20).isActive = true
        badge.heightAnchor.constraint(equalToConstant: 20).isActive = true
        stackView.addArrangedSubview(badge)
    }
    
    return stackView
})

Styling

Style Hierarchy

  1. Global styles (CometChatConversation.style) apply to all instances
  2. Instance styles override global for specific instances

Global Level Styling

import UIKit
import CometChatUIKitSwift

// Apply global styles that affect all CometChatConversations instances
CometChatConversation.style.backgroundColor = UIColor.systemBackground
CometChatConversation.style.titleFont = UIFont.systemFont(ofSize: 17, weight: .bold)
CometChatConversation.style.titleColor = UIColor.label
CometChatConversation.style.listItemTitleTextColor = UIColor.label
CometChatConversation.style.listItemSubTitleTextColor = UIColor.secondaryLabel

// Custom avatar style
let avatarStyle = AvatarStyle()
avatarStyle.backgroundColor = UIColor(red: 0.41, green: 0.32, blue: 0.84, alpha: 1.0)
avatarStyle.cornerRadius = 8
CometChatConversation.style.avatarStyle = avatarStyle

// Custom badge style for unread count
let badgeStyle = BadgeStyle()
badgeStyle.backgroundColor = UIColor.systemRed
badgeStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 10)
CometChatConversation.style.badgeStyle = badgeStyle

Instance Level Styling

import UIKit
import CometChatUIKitSwift

// Create a custom style for a specific instance
var customStyle = ConversationsStyle()
customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0)
customStyle.titleColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0)
customStyle.listItemBackground = UIColor.white
customStyle.listItemCornerRadius = CometChatCornerStyle(cornerRadius: 12)

let conversations = CometChatConversations()
conversations.style = customStyle

Key Style Properties

PropertyTypeDefaultDescription
backgroundColorUIColorCometChatTheme.backgroundColor01Background color of the list
titleFontUIFont?CometChatTypography.setFont(size: 17, weight: .bold)Font for the navigation title
titleColorUIColor?CometChatTheme.textColorPrimaryColor for the navigation title
listItemTitleTextColorUIColorCometChatTheme.textColorPrimaryColor for conversation names
listItemTitleFontUIFontCometChatTypography.Heading4.mediumFont for conversation names
listItemSubTitleTextColorUIColorCometChatTheme.textColorSecondaryColor for last message preview
listItemSubTitleFontUIFontCometChatTypography.Body.regularFont for last message preview
listItemBackgroundUIColor.clearBackground color for list items
listItemCornerRadiusCometChatCornerStyleCometChatCornerStyle(cornerRadius: 0)Corner radius for list items
borderWidthCGFloat0Border width for the component
borderColorUIColor.clearBorder color for the component

Customization Matrix

What to changeWhereProperty/APIExample
Background colorStylebackgroundColorUIColor.systemBackground
Title appearanceStyletitleFont, titleColorUIFont.boldSystemFont(ofSize: 18)
List item lookStylelistItemBackgroundUIColor(white: 0.95, alpha: 1.0)
Unread badgeStylebadgeStyleBadgeStyle() with custom colors
Avatar appearanceStyleavatarStyleAvatarStyle() with custom radius
Hide searchPropertyhideSearchconversations.hideSearch = true
Hide receiptsPropertyhideReceiptsconversations.hideReceipts = true
Custom rowView Slotset(listItemView:)See Custom View Slots section

Props

All props are optional. Sorted alphabetically.

conversationRequestBuilder

Custom request builder for filtering which conversations appear.
TypeConversationRequest.ConversationRequestBuilder?
Defaultnil

customSoundForMessages

Custom sound URL for new message notifications.
TypeURL?
Defaultnil

disableSoundForMessages

Disables notification sounds for new messages.
TypeBool
Defaultfalse

hideBackButton

Hides the back button in the navigation bar.
TypeBool
Defaultfalse

hideDeleteConversationOption

Hides the delete option in conversation actions.
TypeBool
Defaultfalse

hideGroupType

Hides the public/private group type icons.
TypeBool
Defaultfalse

hideNavigationBar

Hides the entire navigation bar.
TypeBool
Defaultfalse

hideReceipts

Hides read/delivered receipt indicators.
TypeBool
Defaultfalse

hideSearch

Hides the search bar.
TypeBool
Defaultfalse

hideUserStatus

Hides online/offline status indicators.
TypeBool
Defaultfalse

selectionMode

Sets the selection mode for multi-select functionality.
TypeSelectionMode
Default.none

textFormatters

Array of text formatters for customizing message text display.
Type[CometChatTextFormatter]
Default[]

Events

EventPayloadFires when
ccConversationDeleteConversationA conversation is deleted from the list

Date Time Formatter

Customize how timestamps appear in the conversation list using the datePattern callback.

Global Level Formatting

import CometChatUIKitSwift

// Set a global date pattern for all conversations instances
CometChatConversations.datePattern = { conversation in
    guard let sentAt = conversation.lastMessage?.sentAt else { return "" }
    
    let date = Date(timeIntervalSince1970: TimeInterval(sentAt))
    let formatter = DateFormatter()
    
    if Calendar.current.isDateInToday(date) {
        formatter.dateFormat = "h:mm a"
    } else if Calendar.current.isDateInYesterday(date) {
        return "Yesterday"
    } else {
        formatter.dateFormat = "MMM d"
    }
    
    return formatter.string(from: date)
}

Instance Level Formatting

import CometChatUIKitSwift

let conversations = CometChatConversations()

conversations.set(datePattern: { conversation in
    guard let sentAt = conversation.lastMessage?.sentAt else { return "" }
    
    let date = Date(timeIntervalSince1970: TimeInterval(sentAt))
    let formatter = DateFormatter()
    
    if Calendar.current.isDateInToday(date) {
        formatter.dateFormat = "HH:mm"  // 24-hour format
    } else if Calendar.current.isDateInYesterday(date) {
        return "Yesterday"
    } else if Calendar.current.isDate(date, equalTo: Date(), toGranularity: .weekOfYear) {
        formatter.dateFormat = "EEEE"  // Day name
    } else {
        formatter.dateFormat = "dd/MM/yy"
    }
    
    return formatter.string(from: date)
})

Available Formatters

FormatterPurposeDefault Format
datePatternFormat for all timestampsh:mm a for today, MMM d for older

Common Customizations

import CometChatUIKitSwift

let conversations = CometChatConversations()

// 24-hour time format
conversations.set(datePattern: { conversation in
    guard let sentAt = conversation.lastMessage?.sentAt else { return "" }
    let date = Date(timeIntervalSince1970: TimeInterval(sentAt))
    let formatter = DateFormatter()
    formatter.dateFormat = "HH:mm"
    return formatter.string(from: date)
})

// Relative time (e.g., "2h ago")
conversations.set(datePattern: { conversation in
    guard let sentAt = conversation.lastMessage?.sentAt else { return "" }
    let date = Date(timeIntervalSince1970: TimeInterval(sentAt))
    let formatter = RelativeDateTimeFormatter()
    formatter.unitsStyle = .abbreviated
    return formatter.localizedString(for: date, relativeTo: Date())
})

Mention Configuration

Configure how @all mentions appear in conversation list items. When a message contains an @all mention, the conversation subtitle displays the mention with a customizable label.

setMentionAllLabel

Sets a custom label for @all mentions displayed in conversation list items.
@discardableResult
public func setMentionAllLabel(_ id: String, _ label: String) -> Self
ParameterTypeDescription
idStringThe identifier for the @all mention (typically “all”)
labelStringThe display text shown to users when @all is mentioned
import CometChatUIKitSwift

let conversations = CometChatConversations()

// Set a custom label for @all mentions
conversations.setMentionAllLabel("all", "Everyone")
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class MentionConfiguredViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let conversations = CometChatConversations()
            .setMentionAllLabel("all", "Team Members")
            .set(onItemClick: { [weak self] conversation, indexPath in
                self?.openMessages(for: conversation)
            })
        
        navigationController?.pushViewController(conversations, animated: true)
    }
    
    private func openMessages(for conversation: Conversation) {
        let messagesVC = CometChatMessages()
        
        if let user = conversation.conversationWith as? User {
            messagesVC.set(user: user)
        } else if let group = conversation.conversationWith as? Group {
            messagesVC.set(group: group)
        }
        
        navigationController?.pushViewController(messagesVC, animated: true)
    }
}

Complete App Example

Here’s a full implementation with tab bar integration showing how to use CometChatConversations in a real app:
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class MainTabBarController: UITabBarController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTabs()
    }
    
    private func setupTabs() {
        // Conversations Tab
        let conversationsVC = ConversationsContainerViewController()
        conversationsVC.tabBarItem = UITabBarItem(
            title: "Chats",
            image: UIImage(systemName: "message"),
            selectedImage: UIImage(systemName: "message.fill")
        )
        
        // Users Tab
        let usersVC = UINavigationController(rootViewController: CometChatUsers())
        usersVC.tabBarItem = UITabBarItem(
            title: "Users",
            image: UIImage(systemName: "person.2"),
            selectedImage: UIImage(systemName: "person.2.fill")
        )
        
        // Groups Tab
        let groupsVC = UINavigationController(rootViewController: CometChatGroups())
        groupsVC.tabBarItem = UITabBarItem(
            title: "Groups",
            image: UIImage(systemName: "person.3"),
            selectedImage: UIImage(systemName: "person.3.fill")
        )
        
        viewControllers = [conversationsVC, usersVC, groupsVC]
    }
}

class ConversationsContainerViewController: UINavigationController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let conversations = CometChatConversations()
        
        // Navigate to messages on tap
        conversations.set(onItemClick: { [weak self] conversation, _ in
            let messagesVC = CometChatMessages()
            
            if let user = conversation.conversationWith as? User {
                messagesVC.set(user: user)
            } else if let group = conversation.conversationWith as? Group {
                messagesVC.set(group: group)
            }
            
            self?.pushViewController(messagesVC, animated: true)
        })
        
        setViewControllers([conversations], animated: false)
    }
}

Troubleshooting

IssueSolution
Empty conversation listEnsure user is logged in and has existing conversations
Conversations not updating in real-timeCheck that CometChat SDK is properly initialized and connected
Navigation not workingVerify navigationController is not nil; embed in UINavigationController
Custom views not appearingEnsure custom view has proper constraints and non-zero frame
Typing indicator not showingVerify hideTypingIndicator is not set to true