Skip to main content
Version: 5.9.0

Quick start

Copy the example as-is and adapt it to your brand.


Minimal example

The fastest way to apply a brand color:

let colors = ChatColors()
colors.link = UIColor(named: "BrandColor") ?? .systemBlue

chatCenterSDK.theme = ChatTheme(colors: colors)

Full branding example

Step 1 — Colors

let colors = ChatColors()

// Primary text and background
colors.main = UIColor(named: "TextPrimary") ?? .label
colors.secondary = UIColor(named: "TextSecondary") ?? .secondaryLabel
colors.background = UIColor(named: "BackgroundPrimary") ?? .systemBackground

// Accent (brand) color
colors.link = UIColor(named: "BrandColor") ?? .systemBlue
colors.positive = UIColor(named: "BrandColor") ?? .systemBlue

// Errors and warnings (keep defaults or set explicitly)
// colors.error = .systemRed
// colors.warning = .systemOrange

Step 2 — Fonts

let typography = ChatTypography()

// Text in message bubbles
typography.message = .systemFont(ofSize: 15, weight: .regular)

// Custom font (if registered in the application):
// typography.message = UIFont(name: "YourFont-Regular", size: 15) ?? .systemFont(ofSize: 15)

// Navigation bar title
typography.title = .systemFont(ofSize: 17, weight: .semibold)

Step 3 — Create the theme

let theme = ChatTheme(colors: colors, typography: typography)

Step 4 — Apply

Lifecycle: set the theme before getChat()

The chat controller reads theme values at creation time. Theme changes after getChat() do not apply to an already-open screen — to apply a new theme, call getChat() again.

// For full getChat() error handling, see getting-started/open_chat.md
func openChat() throws(ChatCenterUIError) {
chatCenterSDK.theme = theme
let chatController = try chatCenterSDK.getChat()
navigationController?.pushViewController(chatController, animated: true)
}

Step 5 — Dark theme (optional)

let darkColors = ChatColors()
darkColors.main = .white
darkColors.secondary = UIColor(white: 0.7, alpha: 1)
darkColors.background = UIColor(named: "BackgroundDark") ?? .black
darkColors.link = UIColor(named: "BrandColorDark") ?? .systemBlue

let darkTheme = ChatTheme(colors: darkColors, typography: typography)
chatCenterSDK.darkTheme = darkTheme

If darkTheme is not set, the SDK uses the light theme in both modes.

Independent light and dark themes

Do not pass the same ChatComponents instance to two themes. ChatComponents is a class, and its styles (navigationBarStyle, inputViewStyle) are stored directly on it — changing the object affects both themes:

// Anti-pattern: shared ChatComponents
let components = ChatComponents()
let lightTheme = ChatTheme(components: components)
let darkTheme = ChatTheme(components: components)

components.navigationBarStyle.backgroundColor = .white
// affects both themes

Correct approach — a separate theme built from its own colors:

let lightTheme = ChatTheme(colors: lightColors, typography: typography)
let darkTheme = ChatTheme(colors: darkColors, typography: typography)

Every call to ChatTheme(colors:images:typography:) creates a new ChatComponents inside.

If you need detailed component customization per theme, create separate ChatComponents instances:

let lightComponents = ChatComponents(colors: lightColors, typography: typography)
lightComponents.navigationBarStyle.backgroundColor = .white

let darkComponents = ChatComponents(colors: darkColors, typography: typography)
darkComponents.navigationBarStyle.backgroundColor = UIColor(white: 0.15, alpha: 1)

chatCenterSDK.theme = ChatTheme(components: lightComponents)
chatCenterSDK.darkTheme = ChatTheme(components: darkComponents)
Icons when using ChatComponents

The images: parameter in ChatComponents(...) and ChatTheme(...) has a default value (ChatImages()). If you have configured icons in a separate ChatImages object, pass it to the initializer explicitly, otherwise the values will reset to the SDK's default SF Symbols.


Full code in a single block

import ChatCenterUI

func configureChatTheme() {
// MARK: - Light theme

let colors = ChatColors()
colors.main = UIColor(named: "TextPrimary") ?? .label
colors.secondary = UIColor(named: "TextSecondary") ?? .secondaryLabel
colors.background = UIColor(named: "BackgroundPrimary") ?? .systemBackground
colors.link = UIColor(named: "BrandColor") ?? .systemBlue
colors.positive = UIColor(named: "BrandColor") ?? .systemBlue

let typography = ChatTypography()
typography.message = .systemFont(ofSize: 15, weight: .regular)
typography.title = .systemFont(ofSize: 17, weight: .semibold)

let theme = ChatTheme(colors: colors, typography: typography)

// MARK: - Dark theme

let darkColors = ChatColors()
darkColors.main = UIColor(named: "TextPrimaryDark") ?? .white
darkColors.secondary = UIColor(named: "TextSecondaryDark") ?? .lightGray
darkColors.background = UIColor(named: "BackgroundDark") ?? UIColor(white: 0.1, alpha: 1)
darkColors.link = UIColor(named: "BrandColorDark") ?? .systemBlue

let darkTheme = ChatTheme(colors: darkColors, typography: typography)

// MARK: - Apply

chatCenterSDK.theme = theme
chatCenterSDK.darkTheme = darkTheme
}

Call configureChatTheme() when initializing the SDK, before opening the chat.

Assignment order: themedarkTheme

Assigning chatCenterSDK.theme silently overwrites the current darkTheme with a reference to the same theme. Always set theme before darkTheme. When swapping both themes dynamically, reassign them in the same order, one after the other.


Where to call it in your application

Set the theme once during SDK initialization, before the first chat open:

// AppDelegate.swift or SceneDelegate.swift
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let sdk = ChatCenterUISDK(providerUid: "your-provider-uid",
appMarker: "your-app-marker",
chatConfig: chatConfig)
sdk.theme = createLightTheme()
sdk.darkTheme = createDarkTheme()
self.chatCenterSDK = sdk
return true
}

Full SDK initialization and patterns for passing the instance between screens are described in SDK initialization and SwiftUI integration.

Do not recreate ChatTheme with the same parameters before every getChat(). Build the theme once and reuse it; when switching dynamically, assign an already-prepared object:

func openChat(with style: AppThemeStyle) throws(ChatCenterUIError) {
chatCenterSDK.theme = themeCache[style]
let chatController = try chatCenterSDK.getChat()
navigationController?.pushViewController(chatController, animated: true)
}

This pattern is used by the demo application when the theme is changed from settings.


Replacing icons

Icons are overridden through ChatImages. Pass the object to ChatTheme together with colors and fonts:

let images = ChatImages()
images.sendButtonImage = ChatImage(system: "paperplane.fill", tintColor: .white)
images.attachButtonImage = ChatImage(system: "plus.circle.fill", tintColor: .white)
images.voiceButtonImage = ChatImage(system: "waveform", tintColor: .white)

let theme = ChatTheme(colors: colors, images: images, typography: typography)

For the full list of icons, see Images.


How to verify the changes

Run the application on the simulator and open the chat. For the dark theme, switch the appearance in Settings → Developer → Dark Appearance, or press ⌘⇧A in the simulator.

A working example with all parameters is in the demo application (MainViewController+Custom.swift).


What's next

TaskSection
All available color tokensColor palette
All font tokens and Figma mappingTypography
Replacing iconsImages
Detailed configuration of buttons and panelsComponents
Targeted customization of a single screenFlows
Something is not workingTroubleshooting
Unclear terminologyGlossary