Skip to main content
Version: 5.9.0

Styles

Quick style lookup

Looking for a style for…Class
Navigation barNavigationBarStyle
Text input fieldChatInputTextStyle
Input panel (buttons + field)ChatInputStyle
Voice recordingChatInputVoiceStyle
Audio playerAudioPlayerStyle
Search barSearchBarStyle
Loading screenChatLoadingStyle
Loading indicatorLoadingIndicatorStyle
Empty chatChatPlaceholderStyle
Loading errorChatPlaceholderErrorStyle
Text messageTextChatMessageStyle
File messageFileChatMessageStyle
Image messageImageChatMessageStyle
Voice messageAudioChatMessageStyle
Survey / ratingSurveyChatMessageStyle
QuoteQuoteStyle
Quick replies (bot)QuickReplyStyle
Search resultSearchChatMessageStyle
Attachment menuChatMenuStyle
Toast notificationToastAlertStyle
Scroll-to-new buttonScrollToMessageButtonStyle

Each element's appearance is controlled through the matching style class. Visual references are available on the Components and User Flow pages in Figma.

Style classDescriptionDesign
Base interface elements
NavigationBarStyleNavigation bar style in the chatUsage
ChatLoadingStyleOverall chat loading screen styleUsage
ChatPlaceholderStyleEmpty chat state style (e.g., no messages)Usage
ChatPlaceholderErrorStyleError display style (e.g., failed to load chat)Usage
LoadingIndicatorStyleLoading indicator style (in messages, actions)Usage
ChatInputStyleMessage input panel style in the chatUsage
ChatInputTextStyleText input container styleUsage
ChatInputVoiceStyleVoice recording element styleUsage
ChatInputQuoteStyleQuote panel above the input field. See the warning belowUsage
SearchBarStyleSearch bar style in the navigation barUsage
ToastAlertStyleToast notification styleUsage
ScrollToMessageButtonStyleScroll-to-new-messages button. alwaysShow (always visible) applies only to the "down" button in ChatFlow.scrollToBottomUnreadMessagesButtonStyle; for the up button this flag is ignored. badgeStyle: ChatTextStyle defines the font and color of the unread count on the badge.
ChatMenuStyleAttachment menu styleUsage
ProgressViewStyleProgress indicator style (file uploads, etc.)
ButtonStyleBase chat button style
TextButtonStyleText-only button (no background)
IconButtonStyleIcon button
NavigationBarButtonStyleNavigation bar button with positioning support
AudioPlayerStyleAudio player style (in chat or standalone)Usage
ChatInputQuoteStyle: limitation in 5.8.x

The titleTextStyle and subtitleTextStyle properties of ChatInputQuoteStyle are not applied in the current version — the quote panel above the input field uses only messageAuthorTextStyle (quote header) and messageTextStyle (quoted message text). See Known limitations.

Search screen styles

NameDescriptionDesign
SearchFlowSearch screen style: searchMessageStyle (SearchChatMessageStyle), notFoundImage, notFoundTextStyleUsage

Message styles

NameDescriptionDesign
ChatMessagesStylesContainer of message styles for one direction (incoming or outgoing)
ChatMessageStyleBase message style in the chat
TextChatMessageStyleText message styleUsage
FileChatMessageStyleFile message styleUsage
SearchChatMessageStyleSearch highlight style in messagesUsage
ImageChatMessageStyleImage-in-message styleUsage
AudioChatMessageStyleAudio message styleUsage
SurveyChatMessageStyleIn-message survey/vote style. questionButtonColor: ChatButtonColor (with three states: normal, highlighted, disabled) replaces the deprecated questionBackgroundColor: UIColor — migration is not 1:1Usage
ScheduleChatMessageStyleSchedule / reminder message styleUsage
OperatorJoinedChatMessageStyleOperator-joined-chat message styleUsage
QuickReplyStyleQuick replies styleUsage
QuoteStyleMessage quote display styleUsage
OpenGraphViewStyleOpenGraph display style in text messagesUsage

System message styles

System messages (centered in the chat) live in the ChatSystemMessagesStyles container, accessible via chatFlow.systemMessages.

PropertyType
operatorJoinedMessageStyleOperatorJoinedChatMessageStyle
scheduleMessageStyleScheduleChatMessageStyle
surveyMessageStyleSurveyChatMessageStyle
dateMessageStyleChatTextStyle
// Set this before the first chat open: on first access to
// chatFlow.systemMessages, all nested styles are initialized from
// the current tokens and stop tracking further token changes.
theme.flows.chatFlow.systemMessages.surveyMessageStyle.questionButtonColor =
ChatButtonColor(normal: .systemBlue, highlighted: .systemTeal, disabled: .systemGray)
theme.flows.chatFlow.systemMessages.dateMessageStyle = ChatTextStyle(
font: .systemFont(ofSize: 12),
color: .secondaryLabel
)

NavigationBarButtonStyle inherits from IconButtonStyle and adds a positioning property. Used for buttons in the top navigation bar of chat and search screens.

Constructor:

let backButton = NavigationBarButtonStyle(
image: ChatImage(system: "chevron.left", tintColor: .white),
position: .left,
components: components
)

Main property:

PropertyTypeDescription
positionNavigationBarButtonPositionButton placement (default .right)

The constructor sets backgroundColor = .clear and tintColor = image.tintColor ?? .systemBlue — so the icon color is taken from the tintColor of the passed ChatImage, and the background is transparent by default. To change the background or color, override these properties on the already-created instance:

backButton.backgroundColor = .black
backButton.tintColor = .yellow

Enum that controls the button placement in the navigation bar:

ValueDescription
.leftPlaced on the left (typically for a "back" button)
.rightPlaced on the right (default)

Example:

let searchButton = NavigationBarButtonStyle(
image: ChatImage(system: "magnifyingglass", tintColor: .systemBlue),
position: .right,
components: components
)

Enums and helper types

QuickReplyMode

Quick reply display mode (QuickReplyStyle.mode):

ValueDescription
.toolbarButtons appear above the input panel
.embedButtons appear inside the chat as part of a message (default)

ChatAlignment

Horizontal alignment (QuickReplyStyle.alignment):

ValueDescription
.leftLeft-aligned
.centerCentered
.rightRight-aligned (default)

ChatInputAlignment

Vertical alignment of buttons in the input panel (ChatInputStyle.alignment):

ValueDescription
.topButtons on top
.centerCentered
.bottomAt the bottom (default)

ChatSurveyIcon

Icon model for surveys (SurveyChatMessageStyle.voteLikeIcon, voteDislikeIcon, voteIcon):

let icon = ChatSurveyIcon(
unselectedImage: ChatImage(system: "hand.thumbsup"),
selectedImage: ChatImage(system: "hand.thumbsup.fill")
)
surveyStyle.voteLikeIcon = icon

In-bubble message styles (TextChatMessageStyle, ImageChatMessageStyle, AudioChatMessageStyle, FileChatMessageStyle, SearchChatMessageStyle, SurveyChatMessageStyle, ScheduleChatMessageStyle, OperatorJoinedChatMessageStyle) inherit common properties from ChatMessageStyle:

PropertyTypeDescription
textStyleChatTextStyleMessage text style
timeTextStyleChatTextStyleSend-time style
editedStatusImageChatImageIcon for an edited message
pendingStatusImageChatImage"Sending" icon
deliveredStatusImageChatImage"Sent" icon
readStatusImageChatImage"Read" icon
errorTextStyleChatTextStyleText style for a send error
errorInfoButtonIconButtonStyle"i" button next to a failed message
errorStatusColorUIColorStatus color on error
errorTimeTextStyleChatTextStyleTime style on error
messageBubbleEndMarginCGFloatMargin from bubble to screen edge
containerRightOffsetCGFloatContainer offset for outgoing messages
containerLeftOffsetCGFloatContainer offset for incoming messages

QuoteStyle, OpenGraphViewStyle and QuickReplyStyle inherit from ChatStyle directly and have their own set of properties.

Unique properties of each message type — in the API Reference.

ChatMessagesStyles properties

Container of message styles for one direction (outcomeMessages / incomeMessages). In addition to nested styles for specific message types (textMessageStyle, imageMessageStyle, audioMessageStyle, fileMessageStyle), it holds shared bubble and avatar properties:

PropertyTypeDescription
bubbleMaskImageChatImageMessage bubble mask shape
bubbleTintColorUIColorBubble background color
bubbleMaskInsetsUIEdgeInsetsBubble mask insets
bubbleErrorColorUIColorBubble color on send error
deletedTextStyleChatTextStyleText style for a deleted message
showAvatarBoolWhether to show the avatar (default true)
avatarSizeCGSizeAvatar size (default 40×40)
avatarOffsetCGFloatAvatar offset
avatarPlaceholderImageChatImagePlaceholder if the avatar fails to load
quoteStyleQuoteStyleStyle of quotes inside the message

When you replace chatFlow.incomeMessages with a new ChatMessagesStyles instance, the SDK automatically mirrors bubbleMaskImage if you didn't set it explicitly — see Glossary.

Assigning bubbleTintColor re-creates the current bubbleMaskImage with the new color — if you change both the mask and the color, set bubbleMaskImage after bubbleTintColor.

You can build a style with the base constructor:

let outcomeMessages = ChatMessagesStyles(components: components)
outcomeMessages.textMessageStyle.textStyle.color = .black
outcomeMessages.showAvatar = showOutcomeAvatar
outcomeMessages.bubbleErrorColor = .red

or with the closure-based builder:

let outcomeMessages = ChatMessagesStyles.build(with: components) { messagesStyle in
messagesStyle.textMessageStyle.textStyle.color = .black
messagesStyle.showAvatar = showOutcomeAvatar
messagesStyle.bubbleErrorColor = .red
}

Mutating properties of an existing style:

// Get the search-screen settings
let searchFlow = theme.flows.searchFlow
searchFlow.navigationBarStyle.hidden = false
searchFlow.navigationBarStyle.searchBarStyle.cancelButtonStyle.tintColor = .white
searchFlow.searchMessageStyle.matchTextStyle.color = .red
searchFlow.notFoundTextStyle = ChatTextStyle(font: typography.message, color: .white)

or through apply:

// Apply search-screen settings
theme.flows.searchFlow.apply {
$0.navigationBarStyle = NavigationBarStyle.build(with: components, configure: {
$0.hidden = false
$0.backButtonColor = .red
})
$0.searchMessageStyle.apply {
$0.matchTextStyle = .init(font: UIFont.systemFont(ofSize: 20), color: .systemGreen)
$0.nextImage = ChatImage(system: "chevron.forward", tintColor: .systemGreen)
}
$0.navigationBarStyle.searchBarStyle.cancelButtonStyle.tintColor = .red
$0.notFoundTextStyle = ChatTextStyle(font: typography.message, color: .red)
}
backButtonColor — application condition

The backButtonColor parameter affects only the custom close button (when showCloseButton=true) and only if the chat is the root controller in the navigation stack. The color of the standard "Back" button in a regular UINavigationController is not controlled by this parameter.

Typical mistakes

Changing a component affects all screens

The most common mistake when working with flows: changing a component via apply affects all screens, because components in ChatComponents are shared objects.

Fix: create a new instance via build instead of mutating the existing one:

// Mutates globally
theme.flows.chatFlow.apply {
$0.inputViewStyle.sendButtonStyle.image = ChatImage(system: "arrow.up")
}

// Targeted override for chatFlow only
let customInputStyle = ChatInputStyle.build(with: components) {
$0.sendButtonStyle.image = ChatImage(system: "arrow.up")
}
theme.flows.chatFlow.inputViewStyle = customInputStyle

The remaining common mistakes (color does not apply, dark theme does not switch, avatar does not hide, font does not change) — with causes and fixes — are in Troubleshooting.