This is beta documentation for Stream Chat IOS SDK v5. For the latest stable version, see the latest version (v4) .

Message Reactions

Reactions Overview

The SwiftUI chat SDK provides a default view that's displayed as an overlay of the message. When you long press on a message, the message reactions overlay is shown. By default, it shows a blurred background and a possibility to react to a message or remove a reaction. Additionally, the reactions overlay has a "message actions" slot, which allows you to perform actions on the message. Both the displayed reactions on a message and the reactions overlay can be replaced by your own views.

When reactions are added to a message, a view displaying the added reactions is shown above the message. When this view is tapped or long-pressed, a new overlay view displaying the list of people who reacted to a message is presented. That view can also be swapped with your own implementation.

Customizing the Message Reactions View

In the SwiftUI SDK, reactions are emoji-based. The availableMessagesReactionEmojis property on Appearance.Images controls which reactions are available in the picker and how they render on messages. It maps MessageReactionType keys to emoji strings:

var images = Appearance.Images()
images.availableMessagesReactionEmojis = [
    "love": "❤️",
    "like": "👍",
    "haha": "😂",
    "wow": "😮",
    "sad": "😢"
]
var appearance = Appearance()
appearance.images = images

let streamChat = StreamChat(chatClient: chatClient, appearance: appearance)

The "More Reactions" picker (shown when tapping the + button in the reactions overlay) uses a separate availableEmojis property on Appearance.Images, which contains the full grid of emojis users can choose from.

You can also change the colors of the reactions by modifying the following properties on ColorPalette:

  • reactionBackground — the background color of reaction bubbles.
  • reactionBorder — the border color of reaction bubbles.
  • reactionText — the text and tint color of reaction icons.

The selected state of a reaction (when the current user has reacted) uses backgroundUtilitySelected.

Here's an example of how to change these values:

var colors = Appearance.ColorPalette()
colors.reactionBackground = UIColor.systemGray6
colors.reactionBorder = UIColor.systemGray4
colors.reactionText = UIColor.label

var appearance = Appearance()
appearance.colorPalette = colors

let streamChat = StreamChat(chatClient: chatClient, appearance: appearance)

By default, the reactions are sorted by their raw value in an alphabetical order. You can change this logic by adding your own implementation of the sortReactions closure in the Utils class.

Here's an example how to achieve this:

let customReactionSort: (MessageReactionType, MessageReactionType) -> Bool = { lhs, rhs in
    // Your custom sorting logic here
    lhs.rawValue < rhs.rawValue
}
let utils = Utils(sortReactions: customReactionSort)
streamChat = StreamChat(chatClient: chatClient, utils: utils)

Changing the Message Reactions View

Alternatively, you can completely swap the ReactionsContainer view with your own implementation. In order to do that, you need to implement the makeMessageReactionView method from the ViewFactory:

public func makeMessageReactionView(
    options: MessageReactionViewOptions
) -> some View {
    CustomReactionsContainer(message: options.message)
}

The MessageReactionViewOptions provides:

  • message – the ChatMessage whose reactions are displayed.
  • onTapGesture – callback when the reactions view is tapped.
  • onLongPressGesture – callback when the reactions view is long-pressed.

Customizing the Reactions Overlay View

The reactions overlay view (shown on long press of a message) also provides access to the message actions. To replace or extend the default message actions, configure them via messageListConfig:

let utils = Utils(
    messageListConfig: MessageListConfig(
        supportedMessageActions: { options in
            MessageAction.defaultActions(for: options)
        }
    )
)
let streamChat = StreamChat(chatClient: chatClient, utils: utils)

Alternatively, you can swap the whole MessageActionsView with your own implementation, by implementing the makeMessageActionsView method in the ViewFactory:

public func makeMessageActionsView(
    options: MessageActionsViewOptions
) -> some View {
    let messageActions = InjectedValues[\.utils].messageListConfig.supportedMessageActions(
        SupportedMessageActionsOptions(
            message: options.message,
            channel: options.channel,
            onFinish: options.onFinish,
            onError: options.onError
        )
    )
    return MessageActionsView(messageActions: messageActions)
}

The MessageActionsViewOptions provides:

  • message – the message for which actions are shown.
  • channel – the channel where the message lives.
  • onFinish – callback when an action finishes successfully.
  • onError – callback when an action fails.

As mentioned at the beginning, when the reactions are tapped or long-pressed, a view with the list of users who reacted to the message is displayed. In order to change this view with your own implementation, you will need to implement the makeReactionsDetailView in the ViewFactory.

func makeReactionsDetailView(options: ReactionsDetailViewOptions) -> some View {
    ReactionsDetailView(message: options.message)
}

The ReactionsDetailViewOptions provides:

  • message – the message whose reaction authors to display.

The background of the reactions overlay is a blurred snapshot of the current channel view, handled internally by the ReactionsOverlayView.

You can customize the snapshot generation logic by providing your own implementation of the SnapshotCreator protocol, which has one method func makeSnapshot(for view: AnyView) -> UIImage. The view parameter is the SwiftUI view which invokes the reactions overlay presentation (the ChatChannelView), while the generated UIImage is used as the blurred background of the overlay.

To inject a custom snapshot creator, pass it to the Utils class:

let snapshotCreator = CustomSnapshotCreator()
let utils = Utils(snapshotCreator: snapshotCreator)
let streamChat = StreamChat(chatClient: chatClient, utils: utils)

Finally, you can swap the whole ReactionsOverlayView with your own implementation. In order to do this, you need to implement the makeReactionsOverlayView method in the ViewFactory. The current snapshot of the message list is provided to you, in case you want to blur it or apply any other effects.

public func makeReactionsOverlayView(
    options: ReactionsOverlayViewOptions
) -> some View {
    ReactionsOverlayView(
        factory: self,
        channel: options.channel,
        currentSnapshot: options.currentSnapshot,
        messageDisplayInfo: options.messageDisplayInfo,
        onBackgroundTap: options.onBackgroundTap,
        onActionExecuted: options.onActionExecuted
    )
}

The ReactionsOverlayViewOptions provides:

  • channel – the channel where the message lives.
  • currentSnapshot – the current snapshot of the message list.
  • messageDisplayInfo – display information about the message (position, size, etc.).
  • onBackgroundTap – callback when the background is tapped to dismiss.
  • onActionExecuted – callback when a message action is executed.