Theming

You can customize the look and feel of all UI components provided by StreamChatUI. The SDK allows you to change the appearance of components such as colors and fonts via the Appearance configuration. Changes to appearance should be done as early as possible in your application lifecycle, the SceneDelegate and AppDelegate are usually the right places to do this. The SDK comes with a singleton object Appearance.default that you can use directly to make changes.

Brand Color

The most basic customization you can do is to change the brand color, and for this one you don't really need the Stream's Appearance configuration, you only need to change the tint color of the UIWindow. If suitable, UI elements respect UIView.tintColor as the main (brand) color. The current tintColor depends on the tint color of the view hierarchy the UI element is presented on.

For example, by changing the tint color of the UIWindow of the app, you can easily modify the brand color of the whole chat UI:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let scene = scene as? UIWindowScene else { return }

        scene.windows.forEach {
          $0.tintColor = .systemPink
        }
    }
}
BeforeAfter
Chat UI with default tint color
Chat UI with pink tint color

Colors and Fonts

The colors and fonts are part of the Appearance configuration type. Since all components have access to this configuration, all components will be impacted by the changes on this configuration.

For example, let's change the color of the messages sent by the current user and the body font. We can do this by simply modifying the values from Appearance.default as early as possible in your application life-cycle:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        ...
        Appearance.default.fonts.body = .italicSystemFont(ofSize: 20)
        Appearance.default.colorPalette.chatBackgroundOutgoing = .yellow
        ...
    }
}

You can find the full reference of both Fonts and ColorPalette respectively.

BeforeAfter
Messages Default Appearance
Messages Adjusted Appearance

You can see the font and the background color of the message has changed. Also note, that the font in the composer text view is also changed, since it uses the same semantic font as the body of the message.

Color Tokens

Accent

TokenDescription
accentPrimaryThe main brand color. Used for interactive elements, buttons, links, and primary actions. Override this to apply your brand color across the SDK.
accentSuccessIndicates a positive or completed state. Used for confirmations and success feedback.
accentErrorIndicates a failure or destructive state. Used for failed messages, validation errors, and deletions.
accentNeutralA mid-tone gray for de-emphasized UI elements.

Background — Elevation

The elevation scale establishes a vertical hierarchy. Higher numbers sit visually closer to the user. In dark mode, values step progressively lighter as depth increases. In light mode, all levels are white.

Elevation tokens in light and dark mode

TokenDescription
backgroundCoreElevation0The base layer. Always white, used as the reference point for the elevation scale. Steps above this gain depth in dark mode through progressively lighter backgrounds.
backgroundCoreElevation1Slightly raised surfaces. Used for content containers that sit directly on the base layer, such as the message list and channel list.
backgroundCoreElevation2Floating and modal surfaces. Used for popovers, dropdowns, dialogs, and any element that interrupts the content flow.
backgroundCoreElevation3Used for badge counts that float above other UI elements.

Background — Surface

TokenDescription
backgroundCoreAppThe outermost application background. Sits behind all surfaces and is generally not overridden directly.
backgroundCoreSurfaceDefaultBackground for sectioned content areas. Used for grouped containers and distinct content regions.
backgroundCoreSurfaceSubtleA slightly receded background. Used for secondary containers or to create soft visual separation.
backgroundCoreSurfaceCardBackground for contained, card-style elements. Matches the surface in light mode but lifts slightly in dark mode to maintain visual separation.
backgroundCoreSurfaceStrongA more prominent background. Used for elements that need to stand out from the main surface.
backgroundCoreInverseThe opposite of the primary surface. Used for tooltips, snackbars, and high-contrast floating elements.
backgroundCoreOnAccentBackground for elements placed on an accent-colored surface. Ensures legibility against brand colors.
backgroundCoreHighlightA tint for drawing attention to content. Used for highlights and pinned messages.
backgroundCoreOverlayLightA light semi-transparent layer. Used to lighten surfaces and for hover states on dark backgrounds.
backgroundCoreOverlayDarkA dark semi-transparent layer. Used for image overlays.
backgroundCoreScrimA heavy semi-transparent layer. Used behind sheets, drawers, and modals to separate them from content.

Background — Utility

TokenDescription
backgroundUtilityPressedA slightly stronger overlay applied during an active press or tap. Provides tactile feedback on interactive elements.
backgroundUtilitySelectedIndicates an active or selected state. Used for selected messages, active list items, and toggled controls.
backgroundUtilityDisabledBackground for non-interactive elements. Flattens the element visually to signal unavailability.

Text

TokenDescription
textPrimaryMain body text. Used for message content, titles, and any text that carries primary meaning.
textSecondarySupporting metadata text. Used for timestamps, subtitles, and secondary labels.
textTertiaryDe-emphasized text. Used for hints, placeholders, and lowest-priority supporting information.
textOnInverseText on inverse-colored surfaces. Flips between light and dark to maintain legibility when the background inverts.
textOnAccentText on accent-colored surfaces. Stays white in both light and dark mode since the accent background does not invert.
textDisabledText for non-interactive or unavailable states. Communicates that an element cannot be interacted with.
textLinkHyperlinks and inline actions. Uses the brand color to signal interactivity within text content.

Border

TokenDescription
borderCoreDefaultStandard border for surfaces and containers. Used for input fields, cards, and dividers on neutral backgrounds.
borderCoreSubtleA lighter border for minimal separation. Used where a full-strength border would feel too heavy.
borderCoreStrongAn emphatic border for elements that need clear definition. Used for focused containers and prominent dividers.
borderCoreInverseBorder on inverse-colored surfaces. Stays legible when the background flips between light and dark mode.
borderCoreOnInverseBorder on inverse-colored surfaces used as a separator element.
borderCoreOnAccentBorder on accent-colored surfaces. Stays white in both light and dark mode since the accent background does not invert.
borderCoreOpacitySubtleA very light transparent border. Used as a frame treatment on images and media attachments.
borderCoreOpacityStrongA stronger transparent border for elements on colored or dark backgrounds. Used for waveform bars and similar treatments.
borderUtilityDisabledBorder for non-interactive elements. Matches the disabled surface to visually flatten the element.
borderUtilityDisabledOnSurfaceBorder for disabled elements on elevated surfaces. Stays visually distinct from the surface without drawing attention.

Avatar

TokenDescription
avatarBackgroundDefaultDefault avatar background color.
avatarPaletteBackground1First palette option for avatar backgrounds.
avatarPaletteText1Text color paired with the first avatar palette background.
avatarTextDefaultDefault text color for avatar initials.

Badge

TokenDescription
badgeBackgroundDefaultBackground for the default badge variant.
badgeBackgroundErrorBackground for error badges indicating failures or critical counts.
badgeBackgroundInverseBackground for badges on light surfaces requiring high contrast.
badgeBackgroundNeutralBackground for neutral, informational badges.
badgeBackgroundOverlayBackground for badges overlaid on media or images.
badgeBackgroundPrimaryBackground for primary-styled badges.
badgeBorderBorder color for badges.
badgeTextText color for badges on default backgrounds.
badgeTextOnAccentText color for badges on accent-colored backgrounds.
badgeTextOnInverseText color for badges on inverse backgrounds.

Button

TokenDescription
buttonPrimaryBackgroundBackground for primary action buttons.
buttonPrimaryBackgroundLiquidGlassBackground for primary buttons with Liquid Glass material.
buttonPrimaryBorderBorder for primary action buttons.
buttonPrimaryTextText color for outlined primary buttons.
buttonPrimaryTextOnAccentText color for filled primary buttons.
buttonSecondaryBackgroundBackground for secondary action buttons.
buttonSecondaryBackgroundLiquidGlassBackground for secondary buttons with Liquid Glass material.
buttonSecondaryBorderBorder for secondary action buttons.
buttonSecondaryTextText color for secondary buttons.
buttonSecondaryTextOnAccentText color for filled secondary buttons.
buttonDestructiveBackgroundBackground for destructive action buttons.
buttonDestructiveBackgroundLiquidGlassBackground for destructive buttons with Liquid Glass material.
buttonDestructiveBorderBorder for destructive action buttons.
buttonDestructiveTextText color for outlined destructive buttons.
buttonDestructiveTextOnAccentText color for filled destructive buttons.

Chat

TokenDescription
chatBackgroundIncomingBubble background for incoming messages.
chatBackgroundOutgoingBubble background for outgoing messages.
chatBackgroundAttachmentIncomingBackground for attachment previews in incoming messages.
chatBackgroundAttachmentOutgoingBackground for attachment previews in outgoing messages.
chatBorderIncomingBorder for incoming message bubbles.
chatBorderOutgoingBorder for outgoing message bubbles.
chatBorderOnChatIncomingBorder for elements inside incoming message bubbles.
chatBorderOnChatOutgoingBorder for elements inside outgoing message bubbles.
chatTextIncomingText color for incoming messages.
chatTextOutgoingText color for outgoing messages.
chatTextLinkLink text color within chat messages.
chatTextSystemText color for system messages.
chatTextTimestampText color for message timestamps.
chatTextTypingIndicatorText color for the typing indicator.
chatTextUsernameText color for usernames in chat.
chatReplyIndicatorIncomingReply thread indicator color for incoming messages.
chatReplyIndicatorOutgoingReply thread indicator color for outgoing messages.
chatPollProgressFillIncomingPoll progress bar fill color in incoming messages.
chatPollProgressFillOutgoingPoll progress bar fill color in outgoing messages.
chatPollProgressTrackIncomingPoll progress bar track color in incoming messages.
chatPollProgressTrackOutgoingPoll progress bar track color in outgoing messages.

Control

TokenDescription
controlCheckboxBorderBorder for checkbox controls.
controlChipTextText color for chip controls.
controlPlaybackThumbBackgroundActiveBackground for the active playback scrubber thumb.
controlPlaybackThumbBackgroundDefaultBackground for the default playback scrubber thumb.
controlPlaybackThumbBorderActiveBorder for the active playback scrubber thumb.
controlPlaybackThumbBorderDefaultBorder for the default playback scrubber thumb.
controlPlayButtonBackgroundBackground for the play button overlay.
controlPlayButtonIconIcon color for the play button overlay.
controlProgressBarFillFill color for progress bars.
controlProgressBarTrackTrack color for progress bars.
controlRadioCheckBackgroundSelectedBackground for selected radio buttons and checkmarks.
controlRadioCheckBorderBorder for radio buttons and checkmarks.
controlRadioCheckIconIcon color for the check indicator in radio buttons and checkmarks.
controlRemoveControlBackgroundBackground for the remove/delete control.
controlRemoveControlBorderBorder for the remove/delete control.
controlRemoveControlIconIcon color for the remove/delete control.

Input

TokenDescription
inputSendIconDisabledSend button icon color when the input is empty or disabled.
inputTextDefaultDefault text color for input fields.
inputTextIconIcon color within input fields.
inputTextPlaceholderPlaceholder text color for input fields.

Presence

TokenDescription
presenceBackgroundOfflineBackground for the offline presence indicator.
presenceBackgroundOnlineBackground for the online presence indicator.
presenceBorderBorder for presence indicator dots.

Reaction

TokenDescription
reactionBackgroundBackground for reaction pills.
reactionBorderBorder for reaction pills.
reactionTextText color for reaction counts.

Utilities

TokenDescription
highlightedColorForColorReturns a highlighted variant of the given color. Used for tap/press states in UIKit views. Type: @Sendable (UIColor) -> UIColor.

Image Assets

The image assets and icons used by buttons also use the Appearance configuration type. For example, let's modify the icon used for the "Send" button:

Appearance.default.images.sendArrow = UIImage(systemName: "arrowshape.turn.up.right")!
BeforeAfter
Custom Send Button
Default Send Button

If the same image is used in multiple places, changing the image in the Appearance object will update it in all places.

You can find the full reference of the Images object here.

Data Formatting

Besides customizing the UI appearance, you can also customize the data formatting of the components. For example, you can change how the channel name is displayed or how the timestamp of messages are formatted.

Below is an example of how to change the channel name and message timestamp formatting.

final class CustomChannelNameFormatter: ChannelNameFormatter {
    func format(
        channel: ChatChannel,
        forCurrentUserId currentUserId: UserId?
    ) -> String? {
        return channel.name ?? channel.lastActiveMembers.map { $0.name ?? $0.id }.joined(separator: ", ")
    }
}

final class CustomMessageTimestampFormatter: MessageTimestampFormatter {
    var dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        return formatter
    }()

    func format(_ date: Date) -> String {
        dateFormatter.string(from: date)
    }
}

Appearance.default.formatters.channelName = CustomChannelNameFormatter()
Appearance.default.formatters.messageTimestamp = CustomMessageTimestampFormatter()

You can find the full reference of the Formatters object here.

For more examples, you can read the Data Formatting page.