Theming

You can customize the look and feel of all UI components provided by StreamChatSwiftUI. The SDK allows you to change the appearance of components such as colors, fonts, and images via the Appearance configuration. Changes to appearance should be done when initializing the StreamChat object, typically in your AppDelegate or at the start of your app lifecycle.

Brand Color

The shortest one-line tweak is to override the accent color in the ColorPalette configuration. UI elements respect this accent color as the main brand color throughout the chat interface — useful when you only need to retint interactive elements.

For example, by customizing the accent color in the Appearance configuration when creating the StreamChat object, you can easily modify the brand color of the whole chat UI:

let apiKeyString = "your_api_key_string"
let config = ChatClientConfig(apiKey: .init(apiKeyString))
let client = ChatClient(config: config)

let newTintColor = UIColor.systemPink
var colors = Appearance.ColorPalette()
colors.accentPrimary = newTintColor
colors.navigationBarTintColor = newTintColor

var appearance = Appearance()
appearance.colorPalette = colors

let streamChat = StreamChat(chatClient: client, appearance: appearance)
BeforeAfter
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 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 through dependency injection, all components will be impacted by the changes on this configuration.

For example, let's change the color of outgoing message bubbles and the body font. We can do this by modifying the values in the Appearance object when initializing StreamChat:

var colors = Appearance.ColorPalette()
colors.chatBackgroundOutgoing = .yellow

var fonts = Appearance.FontsSwiftUI()
fonts.body = .system(size: 20).italic()

var appearance = Appearance()
appearance.colorPalette = colors
appearance.fontsSwiftUI = fonts
let streamChat = StreamChat(chatClient: client, appearance: appearance)
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.

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.

You can find the full reference of the SwiftUI font configuration in FontsSwiftUI and the color definitions in ColorPalette.

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.

TokenDescription
brand50Lightest tint of the brand color ramp.
brand100Very light tint of the brand color ramp. Used for outgoing message bubble backgrounds.
brand150Light tint of the brand color ramp. Used for outgoing attachment backgrounds.
brand200Pale step of the brand color ramp. Used for primary button borders.
brand300Muted step of the brand color ramp. Used for borders inside outgoing message content.
brand400Mid tone of the brand color ramp. Anchors the ramp across light and dark mode.
brand500Primary brand color. Override this and the surrounding steps to apply your brand across the SDK.
brand600Slightly dark shade of the brand color ramp.
brand700Dark shade of the brand color ramp.
brand800Very dark shade of the brand color ramp.
brand900Darkest 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.

TokenDescription
chrome0Base chrome surface. White in light mode, black in dark mode.
chrome50Subtle tint of the chrome (neutral) ramp.
chrome100Light tint of the chrome (neutral) ramp.
chrome150Lifted tint of the chrome (neutral) ramp.
chrome200Pale step of the chrome (neutral) ramp.
chrome300Mid-light step of the chrome (neutral) ramp.
chrome400Mid step of the chrome (neutral) ramp.
chrome500Mid-dark step of the chrome (neutral) ramp.
chrome600Dark step of the chrome (neutral) ramp.
chrome700Very dark step of the chrome (neutral) ramp.
chrome800Darker step of the chrome (neutral) ramp.
chrome900Darkest step of the chrome (neutral) ramp.
chrome1000Extreme chrome value. Black in light mode, white in dark mode.

Accent

TokenDescription
accentPrimaryThe 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.
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.

Navigation

TokenDescription
navigationBarTitleTitle text color in the navigation bar.
navigationBarSubtitleSubtitle text color in the navigation bar.
navigationBarBackgroundBackground color for the navigation bar. Defaults to system appearance when nil.
navigationBarTintColorTint color for navigation bar buttons and icons.
navigationBarGlyphColor for navigation bar glyph elements.

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:

var images = Appearance.Images()
images.composerSend = UIImage(systemName: "arrowshape.turn.up.right")!

var appearance = Appearance()
appearance.images = images
let streamChat = StreamChat(chatClient: client, appearance: appearance)
BeforeAfter
Default Send Button
Custom Send Button

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

The full reference of the Images object can be found 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. For this, you should use the Utils object, which is part of the StreamChat object.

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? {
        if let name = channel.name {
            return name
        }
        return channel.lastActiveMembers
            .map { $0.name ?? $0.id }
            .joined(separator: ", ")
    }
}

let customMessageDateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .short
    return formatter
}()
let utils = Utils(
    dateFormatter: customMessageDateFormatter,
    channelNameFormatter: CustomChannelNameFormatter()
)
let streamChat = StreamChat(
    chatClient: client,
    utils: utils
)