Skip to content

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

If you only need to retint interactive elements you don't have to touch Stream's Appearance configuration — just change the tint color of the UIWindow. UI elements respect UIView.tintColor as the main (brand) color, and 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
        }
    }
}
Before After
Chat UI with default tint color
Chat UI with pink tint color

For systematic theming across the whole SDK, override the brand and chrome ramps on Appearance.default.colorPalette instead — see Brand Ramp and Chrome Ramp below.

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.

Before After
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.

The example above changes a single semantic token. For changes that should propagate to every component derived from your brand or neutral palette, override the brand or chrome ramp instead — see Brand Ramp / Chrome Ramp below.

Color Tokens

Important: Start by adjusting the brand and chrome ramps — most semantic tokens derive from them, so a small number of overrides reskins the whole SDK. Reach for individual semantic tokens only when a specific surface needs to deviate from what the ramps produce.

Brand Ramp

The brand accent color ramp. Most accent and on-brand surfaces derive from these stops.

Token Description
brand50 Lightest tint of the brand color ramp.
brand100 Very light tint of the brand color ramp. Used for outgoing message bubble backgrounds.
brand150 Light tint of the brand color ramp. Used for outgoing attachment backgrounds.
brand200 Pale step of the brand color ramp. Used for primary button borders.
brand300 Muted step of the brand color ramp. Used for borders inside outgoing message content.
brand400 Mid tone of the brand color ramp. Anchors the ramp across light and dark mode.
brand500 Primary brand color. Override this and the surrounding steps to apply your brand across the SDK.
brand600 Slightly dark shade of the brand color ramp.
brand700 Dark shade of the brand color ramp.
brand800 Very dark shade of the brand color ramp.
brand900 Darkest shade of the brand color ramp. Used for text on tinted brand surfaces.

Chrome Ramp

The neutral gray ramp. Most surface, text, and border tokens derive from these stops.

Token Description
chrome0 Base chrome surface. White in light mode, black in dark mode.
chrome50 Subtle tint of the chrome (neutral) ramp.
chrome100 Light tint of the chrome (neutral) ramp.
chrome150 Lifted tint of the chrome (neutral) ramp.
chrome200 Pale step of the chrome (neutral) ramp.
chrome300 Mid-light step of the chrome (neutral) ramp.
chrome400 Mid step of the chrome (neutral) ramp.
chrome500 Mid-dark step of the chrome (neutral) ramp.
chrome600 Dark step of the chrome (neutral) ramp.
chrome700 Very dark step of the chrome (neutral) ramp.
chrome800 Darker step of the chrome (neutral) ramp.
chrome900 Darkest step of the chrome (neutral) ramp.
chrome1000 Extreme chrome value. Black in light mode, white in dark mode.

Accent

Token Description
accentPrimary The main brand color (derived from the brand ramp). Used for interactive elements, buttons, links, and primary actions. Override the brand ramp to cascade across every derived token; override accentPrimary directly only when you want this token to differ from the ramp.
accentSuccess Indicates a positive or completed state. Used for confirmations and success feedback.
accentError Indicates a failure or destructive state. Used for failed messages, validation errors, and deletions.
accentNeutral A 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
Token Description
backgroundCoreElevation0 The 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.
backgroundCoreElevation1 Slightly raised surfaces. Used for content containers that sit directly on the base layer, such as the message list and channel list.
backgroundCoreElevation2 Floating and modal surfaces. Used for popovers, dropdowns, dialogs, and any element that interrupts the content flow.
backgroundCoreElevation3 Used for badge counts that float above other UI elements.

Background — Surface

Token Description
backgroundCoreApp The outermost application background. Sits behind all surfaces and is generally not overridden directly.
backgroundCoreSurfaceDefault Background for sectioned content areas. Used for grouped containers and distinct content regions.
backgroundCoreSurfaceSubtle A slightly receded background. Used for secondary containers or to create soft visual separation.
backgroundCoreSurfaceCard Background for contained, card-style elements. Matches the surface in light mode but lifts slightly in dark mode to maintain visual separation.
backgroundCoreSurfaceStrong A more prominent background. Used for elements that need to stand out from the main surface.
backgroundCoreInverse The opposite of the primary surface. Used for tooltips, snackbars, and high-contrast floating elements.
backgroundCoreOnAccent Background for elements placed on an accent-colored surface. Ensures legibility against brand colors.
backgroundCoreHighlight A tint for drawing attention to content. Used for highlights and pinned messages.
backgroundCoreOverlayLight A light semi-transparent layer. Used to lighten surfaces and for hover states on dark backgrounds.
backgroundCoreOverlayDark A dark semi-transparent layer. Used for image overlays.
backgroundCoreScrim A heavy semi-transparent layer. Used behind sheets, drawers, and modals to separate them from content.

Background — Utility

Token Description
backgroundUtilityPressed A slightly stronger overlay applied during an active press or tap. Provides tactile feedback on interactive elements.
backgroundUtilitySelected Indicates an active or selected state. Used for selected messages, active list items, and toggled controls.
backgroundUtilityDisabled Background for non-interactive elements. Flattens the element visually to signal unavailability.

Text

Token Description
textPrimary Main body text. Used for message content, titles, and any text that carries primary meaning.
textSecondary Supporting metadata text. Used for timestamps, subtitles, and secondary labels.
textTertiary De-emphasized text. Used for hints, placeholders, and lowest-priority supporting information.
textOnInverse Text on inverse-colored surfaces. Flips between light and dark to maintain legibility when the background inverts.
textOnAccent Text on accent-colored surfaces. Stays white in both light and dark mode since the accent background does not invert.
textDisabled Text for non-interactive or unavailable states. Communicates that an element cannot be interacted with.
textLink Hyperlinks and inline actions. Uses the brand color to signal interactivity within text content.

Border

Token Description
borderCoreDefault Standard border for surfaces and containers. Used for input fields, cards, and dividers on neutral backgrounds.
borderCoreSubtle A lighter border for minimal separation. Used where a full-strength border would feel too heavy.
borderCoreStrong An emphatic border for elements that need clear definition. Used for focused containers and prominent dividers.
borderCoreInverse Border on inverse-colored surfaces. Stays legible when the background flips between light and dark mode.
borderCoreOnInverse Border on inverse-colored surfaces used as a separator element.
borderCoreOnAccent Border on accent-colored surfaces. Stays white in both light and dark mode since the accent background does not invert.
borderCoreOpacitySubtle A very light transparent border. Used as a frame treatment on images and media attachments.
borderCoreOpacityStrong A stronger transparent border for elements on colored or dark backgrounds. Used for waveform bars and similar treatments.
borderUtilityDisabled Border for non-interactive elements. Matches the disabled surface to visually flatten the element.
borderUtilityDisabledOnSurface Border for disabled elements on elevated surfaces. Stays visually distinct from the surface without drawing attention.

Avatar

Token Description
avatarBackgroundDefault Default avatar background color.
avatarPaletteBackground1 First palette option for avatar backgrounds.
avatarPaletteText1 Text color paired with the first avatar palette background.
avatarTextDefault Default text color for avatar initials.

Badge

Token Description
badgeBackgroundDefault Background for the default badge variant.
badgeBackgroundError Background for error badges indicating failures or critical counts.
badgeBackgroundInverse Background for badges on light surfaces requiring high contrast.
badgeBackgroundNeutral Background for neutral, informational badges.
badgeBackgroundOverlay Background for badges overlaid on media or images.
badgeBackgroundPrimary Background for primary-styled badges.
badgeBorder Border color for badges.
badgeText Text color for badges on default backgrounds.
badgeTextOnAccent Text color for badges on accent-colored backgrounds.
badgeTextOnInverse Text color for badges on inverse backgrounds.

Button

Token Description
buttonPrimaryBackground Background for primary action buttons.
buttonPrimaryBackgroundLiquidGlass Background for primary buttons with Liquid Glass material.
buttonPrimaryBorder Border for primary action buttons.
buttonPrimaryText Text color for outlined primary buttons.
buttonPrimaryTextOnAccent Text color for filled primary buttons.
buttonSecondaryBackground Background for secondary action buttons.
buttonSecondaryBackgroundLiquidGlass Background for secondary buttons with Liquid Glass material.
buttonSecondaryBorder Border for secondary action buttons.
buttonSecondaryText Text color for secondary buttons.
buttonSecondaryTextOnAccent Text color for filled secondary buttons.
buttonDestructiveBackground Background for destructive action buttons.
buttonDestructiveBackgroundLiquidGlass Background for destructive buttons with Liquid Glass material.
buttonDestructiveBorder Border for destructive action buttons.
buttonDestructiveText Text color for outlined destructive buttons.
buttonDestructiveTextOnAccent Text color for filled destructive buttons.

Chat

Token Description
chatBackgroundIncoming Bubble background for incoming messages.
chatBackgroundOutgoing Bubble background for outgoing messages.
chatBackgroundAttachmentIncoming Background for attachment previews in incoming messages.
chatBackgroundAttachmentOutgoing Background for attachment previews in outgoing messages.
chatBorderIncoming Border for incoming message bubbles.
chatBorderOutgoing Border for outgoing message bubbles.
chatBorderOnChatIncoming Border for elements inside incoming message bubbles.
chatBorderOnChatOutgoing Border for elements inside outgoing message bubbles.
chatTextIncoming Text color for incoming messages.
chatTextOutgoing Text color for outgoing messages.
chatTextLink Link text color within chat messages.
chatTextSystem Text color for system messages.
chatTextTimestamp Text color for message timestamps.
chatTextTypingIndicator Text color for the typing indicator.
chatTextUsername Text color for usernames in chat.
chatReplyIndicatorIncoming Reply thread indicator color for incoming messages.
chatReplyIndicatorOutgoing Reply thread indicator color for outgoing messages.
chatPollProgressFillIncoming Poll progress bar fill color in incoming messages.
chatPollProgressFillOutgoing Poll progress bar fill color in outgoing messages.
chatPollProgressTrackIncoming Poll progress bar track color in incoming messages.
chatPollProgressTrackOutgoing Poll progress bar track color in outgoing messages.

Control

Token Description
controlCheckboxBorder Border for checkbox controls.
controlChipText Text color for chip controls.
controlPlaybackThumbBackgroundActive Background for the active playback scrubber thumb.
controlPlaybackThumbBackgroundDefault Background for the default playback scrubber thumb.
controlPlaybackThumbBorderActive Border for the active playback scrubber thumb.
controlPlaybackThumbBorderDefault Border for the default playback scrubber thumb.
controlPlayButtonBackground Background for the play button overlay.
controlPlayButtonIcon Icon color for the play button overlay.
controlProgressBarFill Fill color for progress bars.
controlProgressBarTrack Track color for progress bars.
controlRadioCheckBackgroundSelected Background for selected radio buttons and checkmarks.
controlRadioCheckBorder Border for radio buttons and checkmarks.
controlRadioCheckIcon Icon color for the check indicator in radio buttons and checkmarks.
controlRemoveControlBackground Background for the remove/delete control.
controlRemoveControlBorder Border for the remove/delete control.
controlRemoveControlIcon Icon color for the remove/delete control.

Input

Token Description
inputSendIconDisabled Send button icon color when the input is empty or disabled.
inputTextDefault Default text color for input fields.
inputTextIcon Icon color within input fields.
inputTextPlaceholder Placeholder text color for input fields.

Presence

Token Description
presenceBackgroundOffline Background for the offline presence indicator.
presenceBackgroundOnline Background for the online presence indicator.
presenceBorder Border for presence indicator dots.

Reaction

Token Description
reactionBackground Background for reaction pills.
reactionBorder Border for reaction pills.
reactionText Text color for reaction counts.

Utilities

Token Description
highlightedColorForColor Returns 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")!
Before After
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.