AI Chatbot Guide v1
AI Chatbot
Version 1

Card view for iOS

Copy link

The card view feature is a UI component designed to enhance chat interfaces by organizing messages into cards. In UI design, a 'card' is a rectangular box that contains and displays a piece of related information cohesively, like a single chat message or a group of messages. This layout not only makes information presentation cleaner and more structured but also allows for greater user engagement and improved aesthetics. The cards are customizable, supporting integration of images, text, and interactive elements, and can be easily adapted to match your brand's style. This page guides you to implement custom message views such as a card view, in chat applications using Sendbird UIKit for Chat.


Copy link

The minimum requirements for iOS are:

  • Sendbird Chat SDK 4.12.2
  • Sendbird Chat UIKit 3.11.0

Implement the card view UI

Copy link

You can implement the card view UI to your app by following the steps below.

Step 1 Configure a CustomViewFactory

Copy link

First, create a custom view class that inherits from UIView. Then, define a Model object implementing Decodable. This model will decode the data from the custom_view field in message.extendedMessagePayload.

// Custom View.
class MyCustomCardView: UIView {
    var data: MyCustomViewModel?
    func bindData(_ data: MyCustomViewModel) { = data
    override func layoutSubviews() {
        self.backgroundColor = .red

// Model: will be auto decodable.
struct MyCustomViewModel: Decodable {
    let name: String
    let data: String

The next step is to create a CustomViewFactory. Implement the SBUExtendedMessagePayloadCustomViewFactory protocol, and override the makeCustomView(_ data, message) method. Also, you can optionally override configure(with, cell) to replace the message bubble area with the custom view as shown in the example below.

class MyCustomViewFactory: SBUExtendedMessagePayloadCustomViewFactory {
    static func makeCustomView(
        _ data: MyCustomViewModel, // type inference.
        message: BaseMessage?
    ) -> UIView? {
        let view = MyCustomCardView()
        return view
    // Optional method.
    static func configure(
        with customView: UIView,
        cell: SBUUserMessageCell
    ) {
        guard let view = customView as? MyCustomCardView else { return }
        // to replace message bubble.
        // custom layout
        view.sbu_constraint(width: 120, height: 120)
            .sbu_constraint(equalTo: cell.mainContainerVStackView,
                            left: 12, right: 12, top: 0, bottom: 0)

Note: If you set the data type in the overridden method as shown in the code above, it should automatically be decoded via type inference. If parsing doesn't seem to work properly, check the console log. The console log will show why parsing fails.

Step 2 Create custom UserMessageCell and setup

Copy link

Define a custom cell class by inheriting from SBUUserMessageCell. Then, override the extendedMessagePayloadCustomViewFactory property to return the factory created above.

class MyCustomUserMessageCell: SBUUserMessageCell {
    override var extendedMessagePayloadCustomViewFactory: SBUExtendedMessagePayloadCustomViewFactoryInternal.Type? {
       return MyCustomViewFactory.self

Step 3 Register custom UserMessageCell in Module list

Copy link

Register the custom user message cell created by configure(delegate, dataSource, theme) in the Module List. This must be done before super.configure(:).

Then, override the generateCellIdentifier(by) method for cell reuse.

extension CustomChannelModule {
    class List: SBUGroupChannelModule.List {
        override func configure(
            delegate: SBUGroupChannelModuleListDelegate,
            dataSource: SBUGroupChannelModuleListDataSource,
            theme: SBUChannelTheme
        ) {
            self.register(userMessageCell: MyCustomUserMessageCell())
               delegate: delegate, 
               dataSource: dataSource, 
               theme: theme

Step4 Update SBUModuleSet with custom module list

Copy link

You can access SBUModuleSet.GroupChannelModule and update its listComponent using the custom module list class.

// It's the Metatype property, update with the `TYPE` of the customized input component.
SBUModuleSet.GroupChannelModule.ListComponent = CustomChannelModule.List.self