Design system
The SDK uses a design system built around the ChatTheme class to configure its user interface.
The SDK supports a light and a dark theme — they are set through the theme and darkTheme properties on the ChatCenterUISDK instance. If darkTheme is not set explicitly, values from theme are used in dark mode.
Assigning theme resets darkTheme — assign darkTheme after theme.
A visual representation of the design system is available as a UIKit in Figma.
The file contains the following pages:
- Foundation — colors, typography, icons (light and dark themes)
- Message Type — all message types in the context of a chat
- Components — Navigation, Status, Button, Bubbles, Input Field, OS UI, Content, Illustration
- User Flow — 40+ screens covering the full user scenario
Start with the Quickstart — a ready-to-use example you can copy and adapt.
The terms "token", "component", and "flow" are described in the Glossary.
Quick example
// Create a theme with custom colors
let colors = ChatColors()
colors.main = .black
colors.link = .systemBlue
let theme = ChatTheme(colors: colors)
// Apply
chatCenterSDK.theme = theme
// chatCenterSDK.darkTheme = darkTheme // optional, if a separate dark theme is set
ChatTheme can be created in two ways:
// From base tokens (colors, fonts, images) — any argument can be omitted
ChatTheme(colors: myColors, typography: myTypography)
// From configured components (for more detailed customization)
ChatTheme(components: myComponents)
What and when to customize
How to choose a customization level?
The design system has three customization levels. Pick the one that fits:
| Task | Level | What to change |
|---|---|---|
| Change the brand color across the SDK | Token | ChatColors |
| Change fonts across the SDK | Token | ChatTypography |
| Replace icons | Token | ChatImages |
| Configure a button, panel, or widget across the SDK | Component | ChatComponents |
| Configure an element only on the chat screen | Flow | ChatFlow |
| Configure an element only on the search screen | Flow | SearchFlow |
All parameters are optional — defaults are used when nothing is set.
Architecture
ChatTheme contains ChatComponents (shared styles reused across all SDK screens) and ChatFlows (per-screen overrides). Components rely on three sets of tokens: ChatColors, ChatTypography, ChatImages.
The full list of ChatComponents fields is in Components. Fine-grained customization through chatFlow / searchFlow is in Flows.
ChatFlows (per-screen) > ChatComponents (global) > ChatColors / ChatTypography / ChatImages (default tokens).
The apply method and the Applicable protocol
All design system objects (ChatTheme, ChatColors, ChatTypography, ChatImages, ChatComponents, styles, and flows) support the apply(_ configure:) method through the Applicable protocol.
theme.flows.chatFlow.apply {
$0.incomeMessages.showAvatar = true
$0.outcomeMessages.showAvatar = false
$0.inputViewStyle.sendButtonStyle.tintColor = .white
}
The apply method returns Self, which lets you configure a freshly created object in a single expression:
let theme = ChatTheme().apply { $0.flows.chatFlow.incomeMessages.bubbleTintColor = .red }
To create a style with a custom configuration, use the build factory method.
The ChatStyle base class
All styles in the SDK inherit from the ChatStyle base class. It implements the Applicable protocol and provides the static build(with:configure:) method for creating subclasses.
Base class properties:
| Property | Type | Description |
|---|---|---|
backgroundColor | UIColor | Element background color |
tintColor | UIColor | Element color (button, icon, etc.) |
cornerRadius | CGFloat | Corner radius (where applicable) |
components | ChatComponents | Reference to the core components for the style |
Each subclass (for example, ChatInputTextStyle, NavigationBarStyle, QuickReplyStyle) inherits these properties and adds its own specific parameters. ChatStyle is not instantiated directly — use a concrete subclass through its constructor with components or through the static build method:
let customStyle = ChatInputTextStyle.build(with: components) { style in
style.backgroundColor = .white
style.cursorColor = .systemBlue
}
Advanced configuration
For fine-grained customization of individual elements, use styles through flows. For example, you can change a button color only on a specific screen without affecting the rest.
Performance recommendations
- Create
ChatThemeonce — at SDK initialization (in AppDelegate / SceneDelegate), not before every chat opening or in a loop - SF Symbols for button icons — they scale without losing quality and are lighter than raster images. Raster PNG/PDF is better for complex custom illustrations
- For adaptive colors, a single
UIColor(dynamicProvider:)is preferable to twoChatColorsobjects withtheme/darkTheme— if only colors differ - Do not reuse a single
ChatComponentsacross differentChatThemeinstances when usingChatTheme(components:)— both themes will reference the same object, and changes in one will affect the other (more in the Quickstart) - iPad and large screens: the SDK adapts to iPad automatically. With fixed font sizes, verify readability — on a large screen the size may need to be increased
- Dynamic Type: if your app supports Dynamic Type, pass scalable fonts through
UIFontMetrics:let baseFont = UIFont.systemFont(ofSize: 15, weight: .regular)
typography.message = UIFontMetrics.default.scaledFont(for: baseFont)
Quick lookup: where to go
| I want to... | File | Class / property |
|---|---|---|
| Apply the brand color | Colors | ChatColors.link |
| Replace the font in bubbles | Typography | ChatTypography.message |
| Replace the send icon | Images | ChatImages.sendButtonImage |
| Configure the navigation bar | Components | ChatComponents.navigationBarStyle |
| Hide the avatar on outgoing messages | Flows | chatFlow.outcomeMessages.showAvatar |
| Change the highlight color in search | Flows | searchFlow.searchMessageStyle.matchTextStyle.color |
| Configure the audio player | Components | ChatComponents.audioPlayerStyle |
| Set a dark theme | Quickstart | chatCenterSDK.darkTheme |
| Find all style classes | Styles | — |
| Something doesn't work | Troubleshooting | — |
| Change the send button color (everywhere) | Components | components.inputViewStyle.sendButtonStyle.tintColor |
| Change the send button color (chat only) | Flows | chatFlow.inputViewStyle.sendButtonStyle.tintColor |
| Configure the empty chat screen | Components | components.chatPlaceholderStyle |