Customization
Appearance
Customize the native Support chat with your app’s colors, typography, welcome text, and dismissal controls. All 14 Reception.Appearance options accept matching values from your Swift variables, including your existing app theme.
Use your app’s theme and variables
You can assign values from your own constants, variables, or theme objects to Reception.shared.appearance. Use a SwiftUI Color for a color property, a String for text or a registered font name, and the matching type for other options, such as Bool or Font.Design. The individual options below list their types and defaults.
For example, place this function in your app’s appearance setup code. Here, AppTheme represents your own app’s theme type, with accentColor, onAccentColor, and backgroundColor properties of type Color, and a fontDesign property of type Font.Design?. Replace these names with your existing theme’s names.
import SwiftUI
import ReceptionKit
@MainActor
func applySupportTheme(_ theme: AppTheme) {
Reception.shared.appearance.accentColor = theme.accentColor
Reception.shared.appearance.onAccentColor = theme.onAccentColor
Reception.shared.appearance.chatBackground = theme.backgroundColor
Reception.shared.appearance.fontDesign = theme.fontDesign
}Call applySupportTheme(yourCurrentTheme) on the main actor after configuring Reception and whenever your app selects or changes a theme. Each assignment takes the current value; it does not bind ReceptionKit to the original variable or observe your theme object. Reassigning local appearance values updates the chat, including while it is open, unless a published remote override takes precedence.
Adaptive asset colors such as Color("SupportAccent") keep their light/dark variants and respond automatically to the chat’s color scheme. A light/dark switch alone does not require reassigning those colors. If your theme changes which color, font, or custom string to use, assign the new value again. Your app also owns localizing custom text.
To keep these values controlled by your app, leave the corresponding dashboard overrides unset, or set Reception.shared.usesRemoteAppearance = false on the main actor to use only local settings. Swift variable names belong in your app’s code; the dashboard accepts explicit values. See Precedence.
Defaults
Without customization, Reception uses your app’s accent color, white text on accent surfaces, system backgrounds, and the system font. It follows your app’s light or dark appearance. The chat title and welcome text use built-in translations. Sheets show a native drag indicator; the optional close button starts hidden.
These settings apply to Reception’s chat, not your app’s support entry button, unread badge, or dashboard interface. The public appearance API does not expose arbitrary layouts, bubble shapes, spacing, or avatars. Your app owns its entry point and surrounding navigation; see Entry point.
Native controls
On iOS 26 and later, the chat title, optional close button, photo button, and message field use native Liquid Glass. Earlier iOS versions use system materials. Message bubbles keep their own background colors. There is no separate appearance option to enable glass; its rendering adapts to the system and presentation.
Set appearance in code
Reception.shared.appearance is a read/write Reception.Appearance value. Read and change it on the main actor, normally during app setup before presenting chat. Reception.Appearance() constructs a fresh set of local defaults.
Place this function in your app’s setup code and call it from a main-actor context. Add a SupportAccent color asset with light and dark variants first.
Example: use your app’s accent
import SwiftUI
import ReceptionKit
@MainActor
func configureSupportAppearance() {
Reception.shared.appearance.accentColor = Color("SupportAccent")
}All short assignment examples below belong inside this main-actor setup function. Named color assets are examples of resources supplied by your app. Every option is configurable in Swift; all except fontFamily are also available in the dashboard.
| Option | Local default |
|---|---|
| accentColor | .accentColor |
| onAccentColor | nil → white |
| chatBackground | nil → system background |
| incomingBackground | nil → secondary system background |
| incomingForeground | nil → primary label color |
| preferredColorScheme | nil → follows app |
| title | Localized “Support” |
| welcomeTitle | Localized “Questions, feedback, or a bug?” |
| welcomeText | Localized “You're chatting directly with our team.” |
| fontDesign | nil → default system design |
| fontFamily | nil → system font |
| showsCloseButton | false |
| closeIcon | .xmark |
| fadesOlderMessages | true |
Precedence
For each option, a valid value in the active published remote appearance overrides your local value. Your local value otherwise applies, using the SDK default when you have left it unset. Reception.shared.usesRemoteAppearance defaults to true.
Remote colors inherit locally for each missing or invalid light/dark variant independently.
Remote text applies only when a valid translation matches the selected app language or the SDK’s supported language match; otherwise the local text applies.
Explicit remote defaults are overrides: “Follow app” clears a local forced color scheme,
falsecan hide a locally enabled close button, and the default font design can replace a local rounded design.A non-
nillocalfontFamilytakes precedence over both local and remotefontDesign.
Reading Reception.shared.appearance returns your local settings, not the merged appearance displayed by the chat. Remote appearance never rewrites that value.
To use only local settings, put this assignment in your main-actor setup function:
Reception.shared.usesRemoteAppearance = falseThis ignores remote settings without deleting their cache. Newly fetched remote settings take effect on the next chat opening, rather than changing the currently open chat. See Remote appearance for publishing and offline behavior.
The comparisons below show focused details from the native chat on iOS 26, using example messages.
Colors and color scheme
All five local color properties accept SwiftUI Color values from your variables, theme objects, or adaptive color assets. See Use your app’s theme and variables for an example and how to handle theme changes. The dashboard supports separate six-digit hex colors for light and dark mode. Test both modes with real messages; light accents may need a dark onAccentColor to keep text readable.
accentColor
Signature: public var accentColor: Color. Default: .accentColor, using your app’s accent. Accepts any SwiftUI Color, including a theme variable.
Colors outgoing text bubble fills, the enabled send button, the review action, and accented controls such as Retry. Older outgoing fills may be lightened by fadesOlderMessages.
In your main-actor setup function:
Reception.shared.appearance.accentColor = Color("SupportAccent")When you change the accent, check that onAccentColor stays readable on it in light and dark mode, and set it too if not.
The dashboard calls this Accent & outgoing bubbles. Assign .accentColor to restore the local default.
onAccentColor
Signature: public var onAccentColor: Color?. Default: nil, which uses white. Accepts any SwiftUI Color, including a theme variable, or nil.
Colors text and symbols on accent surfaces: outgoing message text, the enabled send arrow, and review and paywall button labels and symbols. It does not automatically choose a contrasting color for your accent.
In your main-actor setup function, after adding the named asset:
Reception.shared.appearance.onAccentColor = Color("SupportOnAccent")The dashboard calls this Text on accent. Assign nil to restore white locally.
chatBackground
Signature: public var chatBackground: Color?. Default: nil, which uses Color(uiColor: .systemBackground). Accepts any SwiftUI Color, including a theme variable, or nil.
Sets the chat’s background surface. It does not recolor photos or the full-screen photo viewer’s black background.
In your main-actor setup function, after adding the named asset:
Reception.shared.appearance.chatBackground = Color("SupportBackground")The dashboard calls this Chat background. Assign nil to restore the adaptive system background locally.
incomingBackground
Signature: public var incomingBackground: Color?. Default: nil, which uses Color(uiColor: .secondarySystemBackground). Accepts any SwiftUI Color, including a theme variable, or nil.
Sets incoming text bubble, review card, and paywall card backgrounds. Pair it with an incoming text color that remains readable in both modes.
In your main-actor setup function, after adding the named asset:
Reception.shared.appearance.incomingBackground = Color("SupportIncoming")The dashboard calls this Incoming bubbles. Assign nil to restore the adaptive secondary system background locally.
incomingForeground
Signature: public var incomingForeground: Color?. Default: nil, which uses .primary. Accepts any SwiftUI Color, including a theme variable, or nil.
Sets incoming message text and the body text of review and paywall cards. Card button labels use onAccentColor; secondary labels keep their own colors.
In your main-actor setup function, after adding the named asset:
Reception.shared.appearance.incomingForeground = Color("SupportIncomingText")The dashboard calls this Incoming text. Assign nil to restore the adaptive primary label color locally.
preferredColorScheme
Signature: public var preferredColorScheme: ColorScheme?. Default: nil. Allowed values: nil, .light, .dark.
nil follows the app’s inherited color scheme. .light or .dark forces the chat’s appearance, including the variant selected by adaptive colors. Presented chat applies a presentation preference; embedded chat applies the scheme to its content.
In your main-actor setup function:
Reception.shared.appearance.preferredColorScheme = .darkThe dashboard offers Follow app, Always light, or Always dark. Assign nil to follow the app locally. A published Follow app value overrides a local .light or .dark; clearing the remote override instead inherits the local choice.
Title and welcome text
title
Signature: @MainActor public var title: String { get set }. Default: the localized “Support” title. Accepts any local String; there is no local length validation. Dashboard translations are limited to 80 characters.
Sets the chat’s navigation title. Keep it short enough to fit the navigation bar.
In your main-actor setup function, using copy from your app’s string catalog:
Reception.shared.appearance.title = String(localized: "Help")A custom string is displayed as supplied; see Localization of texts and Return to defaults before replacing built-in copy.
welcomeTitle
Signature: @MainActor public var welcomeTitle: String { get set }. Default: the localized “Questions, feedback, or a bug?” headline. Accepts any local String; there is no local length validation. Dashboard translations are limited to 160 characters.
Sets the heading in the empty chat. It is not an introductory message inserted into conversation history.
In your main-actor setup function, using copy from your app’s string catalog:
Reception.shared.appearance.welcomeTitle = String(localized: "How can we help?")Leave it unset to retain the built-in translated heading; resetting an assigned string requires the approach in Return to defaults.
welcomeText
Signature: @MainActor public var welcomeText: String { get set }. Default: the localized “You're chatting directly with our team.” text. Accepts any local String; there is no local length validation. Dashboard translations are limited to 1,000 characters.
Sets the explanatory text below the empty chat’s welcome heading. It does not set an automatic reply or alter existing messages.
In your main-actor setup function, using copy from your app’s string catalog:
Reception.shared.appearance.welcomeText = String(localized: "Tell us what you need help with.")Leave it unset to retain the built-in translated text; see Return to defaults after assigning custom copy.
Typography
fontDesign
Signature: public var fontDesign: Font.Design?. Default: nil, which uses the default system design. Allowed values: nil, .default, .rounded, .serif, .monospaced.
Selects the system font design used by chat text, including the title, message text, composer, and status labels. System symbols and native controls retain their own rendering. A non-nil fontFamily takes precedence.
In your main-actor setup function:
Reception.shared.appearance.fontDesign = .roundedAssign nil to restore the local default system design. Also clear fontFamily if you previously selected a custom font.
fontFamily
Signature: public var fontFamily: String?. Default: nil, which uses the system font. Accepts a custom font name string or nil.
ReceptionKit passes this name to SwiftUI’s Font.custom. When your app uses a custom font for its main UI text, reuse the exact registered font/PostScript name already working in the host’s Font.custom or UIFont(name:size:) call, preferably through its existing font constant. Despite the property name, the value is a technical font name: its display label, .ttf/.otf filename, and family name can differ. Do not derive the value from those labels.
If you need to find the name, call UIFont.fontNames(forFamilyName:) in the running host app to list the registered names for its existing family, then confirm your chosen name returns a non-nil font from UIFont(name:size:). Preserve the host’s existing font registration; do not add fonts or assets just for support chat. If the host uses the system font, leave fontFamily as nil; use fontDesign only to match an existing system design.
Custom fonts scale with Dynamic Type. This property overrides fontDesign, including a design published from the dashboard.
In your main-actor setup function, using Georgia, which is already registered on iOS:
Reception.shared.appearance.fontFamily = "Georgia"Available only in Swift; the dashboard cannot upload or select a custom font. Assign nil to return to the resolved system fontDesign. An empty string is still a non-nil custom font name, not a reset.
Dismissal and message behavior
showsCloseButton
Signature: public var showsCloseButton: Bool. Default: false. Allowed values: true, false.
When true, a presented chat shows a trailing close button that dismisses its presentation. The SDK-owned sheet and a host-owned SwiftUI sheet supply this presentation context. The sheet’s native drag indicator stays visible regardless of this setting. Hiding the button does not disable swipe-to-dismiss.
In your main-actor setup function:
Reception.shared.appearance.showsCloseButton = trueAssign false to restore the local default. A directly embedded chat outside a presentation does not gain a close button; your app supplies its navigation or dismissal controls. Reception.shared.closeChat() dismisses an SDK-owned sheet, not a host-owned ReceptionChatView. See Entry point for presentation ownership.
closeIcon
Signature: public var closeIcon: Reception.CloseIcon. Default: .xmark. Allowed values: .xmark, .chevronDown, .arrowDown. Their raw symbol names are xmark, chevron.down, and arrow.down.
Selects the optional chat close button’s symbol. It does not change the dismissal action, show the button by itself, or change the photo viewer’s close symbol.
In your main-actor setup function:
Reception.shared.appearance.showsCloseButton = true
Reception.shared.appearance.closeIcon = .chevronDownAssign .xmark to restore the local default.
fadesOlderMessages
Signature: public var fadesOlderMessages: Bool. Default: true. Allowed values: true, false.
Lightens older outgoing text bubble fills toward white. The newest outgoing text bubble keeps the accent color. Text, photos, and incoming bubbles are unaffected. Increase Contrast disables fading. Sending-state dimming is separate.
In your main-actor setup function:
Reception.shared.appearance.fadesOlderMessages = falsefalse keeps outgoing fills at the accent color; assign true to restore local age-based fading.
Localization of texts
Leave the three text properties unset to retain built-in translations. An assigned String is a local override, even when its contents equal the English default. ReceptionKit does not translate that string for you. Resolve custom strings through your app’s string catalog and reassign them when your app’s own language selection changes.
See Language for every supported language code, Reception.shared.languageOverride, and matching rules. See Remote appearance for dashboard translation selection, limits, and fallbacks.
Dashboard appearance
Publish colors, text, typography, and behavior from the dashboard without shipping a new app build. The Remote appearance guide explains the editor, draft and published states, language-specific text, caching, and when changes become visible. Custom font files and fontFamily remain host-app resources.
Return to defaults
Optional color properties, preferredColorScheme, fontDesign, and fontFamily reset locally with nil. Restore nonoptional properties using their defaults listed above.
Assigning an empty string or the displayed default doesn't restore automatic translation. For example, Reception.shared.appearance.title = Reception.Appearance().title copies the current translated text into a fixed override; it does not restore future automatic language changes.
To restore automatic localized defaults, construct a fresh Reception.Appearance and reapply only the customization you want to keep. Put this in your main-actor setup function to keep an accent while restoring all other local defaults:
var appearance = Reception.Appearance()
appearance.accentColor = Color("SupportAccent")
Reception.shared.appearance = appearanceFor a complete local reset, use this assignment in the same main-actor context:
Reception.shared.appearance = Reception.Appearance()These assignments do not disable remote appearance or clear published settings. In the dashboard, removing an override restores inheritance from the app’s local value. Restore defaults clears the editor’s draft; publish the reset to deliver it. It does not reset your Swift configuration. See Remote appearance.
Verify your customization
Open both an empty chat and a chat containing incoming and outgoing messages. Check light and dark mode, larger Dynamic Type sizes, Increase Contrast, your supported languages, and your actual sheet or embedded presentation.
If an option appears ineffective, check whether a published remote override applies. For fonts, clear fontFamily before checking fontDesign. For close controls, confirm that the chat is presented and showsCloseButton resolves to true. For welcome text, inspect an empty chat. After publishing dashboard changes, allow the refresh to complete and reopen chat; the dashboard preview cannot reproduce your app’s local overrides or bundled fonts.