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
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)
ChatComponentsThe 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.
theme → darkThemeAssigning 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
| Task | Section |
|---|---|
| All available color tokens | Color palette |
| All font tokens and Figma mapping | Typography |
| Replacing icons | Images |
| Detailed configuration of buttons and panels | Components |
| Targeted customization of a single screen | Flows |
| Something is not working | Troubleshooting |
| Unclear terminology | Glossary |