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

Message Display Options

What is MessageDisplayOptions?

MessageDisplayOptions is a configuration struct that controls the visual behavior and appearance of individual messages in the message list. It is passed into the MessageListConfig via the messageDisplayOptions parameter.

Here is the minimal setup:

let messageDisplayOptions = MessageDisplayOptions()
let messageListConfig = MessageListConfig(messageDisplayOptions: messageDisplayOptions)
let utils = Utils(messageListConfig: messageListConfig)
let streamChat = StreamChat(chatClient: chatClient, utils: utils)

Because every parameter has a default value, you only need to specify the ones you want to change.

Parameter Reference

Here is an overview of all the parameters available in MessageDisplayOptions:

ParameterTypeDefault
showAvatarsBooltrue
showAvatarsInGroupsBooltrue
showMessageDateBooltrue
showAuthorNameBooltrue
animateChangesBooltrue
dateLabelSizeCGFloat40
lastInGroupHeaderSizeCGFloat0.5
newMessagesSeparatorSizeCGFloat1
minimumSwipeGestureDistanceCGFloat50
currentUserMessageTransitionAnyTransition.identity
otherUserMessageTransitionAnyTransition.identity
shouldAnimateReactionsBooltrue
reactionsPlacementReactionsPlacement.overlay
showOriginalTranslatedButtonBoolfalse
messageLinkDisplayResolver(ChatMessage) -> [NSAttributedString.Key: Any]Returns [:]
spacerWidth(CGFloat) -> CGFloatReturns 0
reactionsTopPadding(ChatMessage) -> CGFloatReturns 0
dateSeparator(ChatMessage, ChatMessage) -> Date?Returns nil

showAvatars

Controls whether avatars are shown next to messages in the message list. The default is true.

let messageDisplayOptions = MessageDisplayOptions(showAvatars: false)

showAvatarsInGroups

Controls whether avatars are shown when messages are displayed in groups. When groupMessages is enabled in MessageListConfig, consecutive messages from the same user are grouped together. This parameter controls whether the avatar is shown for each message in such a group. The default is true.

let messageDisplayOptions = MessageDisplayOptions(showAvatarsInGroups: false)

showMessageDate

Controls whether the date and time label is shown for each message. The default is true.

let messageDisplayOptions = MessageDisplayOptions(showMessageDate: false)

showAuthorName

Controls whether the author name is shown above messages sent by other participants. The default is true.

let messageDisplayOptions = MessageDisplayOptions(showAuthorName: false)

animateChanges

Controls whether changes to the message list (such as new messages appearing) are animated. The default is true. Setting this to false disables animations, which can be useful for accessibility or performance reasons.

let messageDisplayOptions = MessageDisplayOptions(animateChanges: false)

dateLabelSize

The font size of the date/time label shown next to a message. The default is 40.

let messageDisplayOptions = MessageDisplayOptions(dateLabelSize: 40)

lastInGroupHeaderSize

The height of the spacing element shown below the last message in a group. This thin divider provides visual separation between message groups. The default is 0.

let messageDisplayOptions = MessageDisplayOptions(lastInGroupHeaderSize: 2)

newMessagesSeparatorSize

The height of the separator shown between read and unread messages. The default is 50.

let messageDisplayOptions = MessageDisplayOptions(newMessagesSeparatorSize: 50)

minimumSwipeGestureDistance

The minimum distance (in points) the user must swipe on a message before the swipe-to-reply gesture is recognized. The default is 50.

let messageDisplayOptions = MessageDisplayOptions(minimumSwipeGestureDistance: 30)

currentUserMessageTransition

The SwiftUI transition applied when messages sent by the current user appear in the list. The default is .identity (no animation). You can use any built-in transition such as .scale, .opacity, or .slide, or create a custom one.

var customTransition: AnyTransition {
    .scale.combined(with:
        AnyTransition.asymmetric(
            insertion: .move(edge: .trailing),
            removal: .move(edge: .leading)
        )
    )
}

let messageDisplayOptions = MessageDisplayOptions(
    currentUserMessageTransition: customTransition
)

otherUserMessageTransition

The SwiftUI transition applied when messages sent by other participants appear in the list. The default is .identity. Works the same way as currentUserMessageTransition.

let messageDisplayOptions = MessageDisplayOptions(
    otherUserMessageTransition: .opacity
)

You can also use the same custom transition for both the current user and other users:

var customTransition: AnyTransition {
    .scale.combined(with:
        AnyTransition.asymmetric(
            insertion: .move(edge: .trailing),
            removal: .move(edge: .leading)
        )
    )
}

let messageDisplayOptions = MessageDisplayOptions(
    currentUserMessageTransition: customTransition,
    otherUserMessageTransition: customTransition
)

shouldAnimateReactions

Controls whether reactions animate when they are added or removed from a message. The default is true.

let messageDisplayOptions = MessageDisplayOptions(shouldAnimateReactions: false)

reactionsPlacement

Controls where the reactions overlay is placed relative to the message bubble. The ReactionsPlacement enum has two cases:

  • .overlay — reactions float above the message bubble (default).
  • .bottom — reactions are shown below the message bubble.
let messageDisplayOptions = MessageDisplayOptions(reactionsPlacement: .bottom)

showOriginalTranslatedButton

Controls whether a button is shown on translated messages that allows the user to toggle between the translated and the original text. The default is false.

let messageDisplayOptions = MessageDisplayOptions(showOriginalTranslatedButton: true)

messageLinkDisplayResolver

A closure that returns the text attributes (such as font, color, and weight) used to render links inside messages. The closure receives the ChatMessage as context, allowing you to style links differently depending on the sender or other message properties. By default, links use the standard system link appearance.

Here is an example that changes the link color based on whether the message was sent by the current user:

let messageDisplayOptions = MessageDisplayOptions(messageLinkDisplayResolver: { message in
    let color = message.isSentByCurrentUser ? UIColor.red : UIColor.green

    return [
        NSAttributedString.Key.foregroundColor: color
    ]
})
let messageListConfig = MessageListConfig(messageDisplayOptions: messageDisplayOptions)
let utils = Utils(messageListConfig: messageListConfig)

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

spacerWidth

A closure that returns the width of the spacer placed on the opposite side of a message bubble. This controls how wide the message bubble can be, since the spacer compresses it from one side. The closure receives the total available width and should return the spacer width. By default the spacer has zero width, allowing the bubble to fill the available space.

let messageDisplayOptions = MessageDisplayOptions(
    spacerWidth: { availableWidth in
        availableWidth * 0.25
    }
)

reactionsTopPadding

A closure that returns the top padding applied to the reactions overlay for a given message. This lets you adjust the vertical position of the reactions relative to the message bubble on a per-message basis. The default returns 20.

let messageDisplayOptions = MessageDisplayOptions(
    reactionsTopPadding: { message in
        message.isSentByCurrentUser ? 4 : 8
    }
)

dateSeparator

A closure that determines whether a date separator should be shown between two consecutive messages, and what date it should display. The closure receives the two adjacent messages (earlier and later) and returns an optional Date. If nil is returned, no separator is shown. The default returns nil, meaning no custom date separators are injected (the SDK's built-in dateIndicatorPlacement logic applies instead).

let messageDisplayOptions = MessageDisplayOptions(
    dateSeparator: { previousMessage, nextMessage in
        let calendar = Calendar.current
        if !calendar.isDate(previousMessage.createdAt, inSameDayAs: nextMessage.createdAt) {
            return nextMessage.createdAt
        }
        return nil
    }
)