Customization
Appearance
Customize the native Support chat with your app’s colors, typography, welcome text and icon, and dismissal controls. Every Reception.Appearance option accepts matching values from your Swift variables, including your existing app theme. Android apps set the same options in Kotlin; see Appearance on Android.
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, an Image from your asset catalog for welcomeIcon or closeImage, 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 Reception
@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 the SDK 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 Reception
@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 below is configurable in Swift; all except fontFamily are also available in the dashboard. Team photos and names and review, offer and link card styles are set only 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.” |
| welcomeIcon | nil → chat bubbles symbol |
| welcomeIconColor | nil → tertiary label color |
| welcomeIconSize | nil → 44 points |
| welcomeIconCornerRadius | 0 → square corners |
| welcomeIconOffset | .zero |
| hidesTitle, hidesWelcomeTitle, hidesWelcomeText, hidesPushStatus | false |
| fontDesign | nil → default system design |
| fontFamily | nil → system font |
| showsCloseButton | false |
| closeIcon | .xmark |
| closeImage | nil → closeIcon |
| 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.Dashboard visibility can show or hide the title, welcome heading, welcome text, and icons, including elements hidden in Swift. Use app default restores local visibility.
A published font design uses that system font instead of a local
fontFamily. Use app default restores the app’s custom font or local design.
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.
Hiding text
Signatures: public var hidesTitle: Bool, public var hidesWelcomeTitle: Bool, public var hidesWelcomeText: Bool, public var hidesPushStatus: Bool. Default: false for each.
hidesTitle removes the navigation title. hidesWelcomeTitle and hidesWelcomeText remove the heading or the text from the empty chat. hidesPushStatus removes the “You’ll get a notification when we reply.” line under the person’s latest message; the notification card still appears. Dashboard Visibility → Show or Hide overrides these local choices; Use app default inherits them.
In your main-actor setup function:
Reception.shared.appearance.hidesWelcomeText = trueWelcome icon
welcomeIcon
Signature: public var welcomeIcon: Reception.WelcomeIcon?. Default: nil, using the built-in chat bubbles symbol. Allowed values: .symbol(_:) with an SF Symbol name, .image(_:) with a SwiftUI Image, and .hidden.
Sets the icon above the welcome heading. Images keep their own colors and fit inside a square of welcomeIconSize. An image from your asset catalog shows immediately, with no upload or download.
In your main-actor setup function, using an image asset from your app:
Reception.shared.appearance.welcomeIcon = .image(Image("SupportLogo")).hidden removes the local icon; nil restores the built-in symbol. A published symbol or image can replace the local choice. Dashboard Visibility → Show restores the built-in symbol when the local icon is hidden and no remote icon is selected; Hide hides any icon.
welcomeIconColor
Signature: public var welcomeIconColor: Color?. Default: nil, using the tertiary label color. Applies to symbols, not images.
Reception.shared.appearance.welcomeIconColor = Color("SupportAccent")welcomeIconSize
Signature: public var welcomeIconSize: CGFloat?. Default: nil, using 44 points. The size scales with Dynamic Type. Dashboard values are limited to 16–160 points.
Reception.shared.appearance.welcomeIconSize = 80welcomeIconCornerRadius
Signature: public var welcomeIconCornerRadius: CGFloat. Default: 0 (square corners). Values are clamped to 0–80 points before Dynamic Type scaling, then limited to half the image's shortest edge.
Rounds the actual edges of local and uploaded welcome images without stretching them or changing their aspect ratio. SF Symbols are unaffected. Transparent padding inside the original image remains part of that image.
In your main-actor setup function, using an image asset from your app:
Reception.shared.appearance.welcomeIcon = .image(Image("SupportLogo"))
Reception.shared.appearance.welcomeIconSize = 80
Reception.shared.appearance.welcomeIconCornerRadius = 16In the dashboard, Welcome icon → Image corner radius overrides this value, even when the image itself comes from your app. An explicit 0 restores square corners. Use app corner radius removes only the remote radius override. Set the local property to 0 to reset it in Swift.
welcomeIconOffset
Signature: public var welcomeIconOffset: CGSize. Default: .zero. Moves the icon from its centered position by the given points; the heading and text stay in place. Dashboard values are limited to ±120 points on each axis. Center publishes a zero offset, overriding the app’s position; Use app position restores the local offset.
Reception.shared.appearance.welcomeIconOffset = CGSize(width: 0, height: -12)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 local fontFamily takes precedence over local fontDesign; an explicitly published dashboard font design overrides both.
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.
The SDK 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 local fontDesign. An explicitly published dashboard font design uses the selected system font instead; Use app default restores your custom font.
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. An explicitly published close symbol replaces a local closeImage; a published custom close image takes precedence over the symbol.
In your main-actor setup function:
Reception.shared.appearance.showsCloseButton = true
Reception.shared.appearance.closeIcon = .chevronDownAssign .xmark to restore the local default.
closeImage
Signature: public var closeImage: Image?. Default: nil, using closeIcon. Accepts a SwiftUI Image.
Replaces the close button’s symbol with an image from your app, drawn in its own colors at 18 points. It shows immediately, with no upload or download. Like closeIcon, it does not show the button by itself or change the photo viewer’s close symbol.
In your main-actor setup function, using an image asset from your app:
Reception.shared.appearance.showsCloseButton = true
Reception.shared.appearance.closeImage = Image("SupportClose")Assign nil to return to closeIcon locally. A published close symbol or image overrides this local image; leave both dashboard choices unset to use it.
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.
Appearance on Android
The Android SDK has every option above on Reception.appearance, a mutable Reception.Appearance. Set options right after Reception.configure or assign a new Reception.Appearance(); changes apply to an open chat at once. Dashboard overrides, precedence and usesRemoteAppearance work as described on this page.
| Option | Kotlin type | Android default |
|---|---|---|
accentColor, onAccentColor, chatBackground, incomingBackground, incomingForeground, welcomeIconColor | ReceptionColor? | As on iOS, except the accent: see below |
preferredColorScheme | Reception.ColorScheme? (LIGHT, DARK) | null, following the system dark theme |
title, welcomeTitle, welcomeText | String | Built-in translations |
welcomeIcon | Reception.WelcomeIcon? (symbol, image, resource, hidden) | null, the chat bubbles symbol |
welcomeIconSize, welcomeIconCornerRadius, welcomeIconOffset | Dp?, Dp, DpOffset | 44 dp, 0.dp, no offset |
fontDesign | Reception.FontDesign? | null, Roboto |
fontFamily | FontFamily? (Compose) | null, system font |
closeIcon, closeImage, closeImageResource | Reception.CloseIcon, Painter?, Int? (@DrawableRes) | XMARK, null, null |
showsCloseButton, fadesOlderMessages, hidesTitle, hidesWelcomeTitle, hidesWelcomeText, hidesPushStatus | Boolean | As on iOS |
Differences from iOS:
Accent. Without
accentColor, the SDK’s sheet uses the device’s dynamic color (Material You) on Android 12 and later and blue below. An embeddedReceptionChatViewuses theprimarycolor of the enclosingMaterialThemeinstead. Material 3’s unthemed default scheme counts as no theme. If your app’s theme uses dynamic color, leaveaccentColorandonAccentColorunset so the chat matches the app; set them only for fixed brand colors.Light and dark. Every color is a
ReceptionColor, the Android counterpart of an adaptive asset color:ReceptionColor(color)for one color in both modes,ReceptionColor(light = …, dark = …)for a pair of Compose colors, orReceptionColor.resource(R.color.brand)for a color resource whosevalues-nightvariant is the dark one. The chat picks the variant of the mode it draws in, includingpreferredColorScheme, so a light/dark switch needs no reassignment. Java code, which cannot pass Compose colors, usesReceptionColor.argb(light, dark)with ARGB ints. An embedded chat follows the enclosing theme’s background for light or dark mode unlesspreferredColorSchemeis set.Fonts.
fontFamilyis a ComposeFontFamilybuilt from your bundled fonts, such asFontFamily(Font(R.font.inter_regular), Font(R.font.inter_bold, FontWeight.Bold)). Android has no rounded system font, soFontDesign.ROUNDEDdraws the default font. Text scales with the system font size.Symbols.
WelcomeIcon.symbol(name)takes the SF Symbols name the dashboard uses, such as"star.fill"; the SDK draws the matching Material Symbols icon for every symbol the dashboard offers. Any other name shows the built-in chat bubbles icon.Images.
WelcomeIcon.resource(R.drawable.support_logo)andcloseImageResource = R.drawable.closetake a drawable resource, vector or bitmap, and work without Compose code.WelcomeIcon.image(painter)andcloseImagetake a ComposePainterinstead. Images keep their own colors. There is one close image: settingcloseImagereplacescloseImageResourceand the other way round.Sheet. The SDK’s sheet is a Material 3 bottom sheet with a drag handle.
showsCloseButtonadds the close button beside the title; the handle, dragging, tapping outside and Back still close it.
// Right after Reception.configure, with values from your app's theme.
Reception.appearance.accentColor = ReceptionColor.resource(R.color.brand)
Reception.appearance.incomingBackground = ReceptionColor(light = Color(0xFFF1F0F7), dark = Color(0xFF2A2833))
Reception.appearance.preferredColorScheme = Reception.ColorScheme.DARK
Reception.appearance.fontFamily = FontFamily(Font(R.font.inter_regular), Font(R.font.inter_bold, FontWeight.Bold))
Reception.appearance.welcomeIcon = Reception.WelcomeIcon.resource(R.drawable.support_logo)
Reception.appearance.showsCloseButton = true
Reception.appearance.closeIcon = Reception.CloseIcon.CHEVRON_DOWNR.color.brand and R.drawable.support_logo stand for your app’s resources; for a symbol instead of an image, use Reception.WelcomeIcon.symbol("star.fill").
To restore every local default, assign Reception.appearance = Reception.Appearance(); setting a nullable option to null restores its default.
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. The SDK 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, fontFamily, welcomeIcon, welcomeIconSize, and closeImage 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 a local system font design, clear fontFamily; for a local custom font, leave dashboard Font style on Use app default. 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.