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.
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:
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:
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.
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.
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.
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.
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.
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)