Theming, branding, and localization
Use the MobileIDTheme APIs and the SDK localization override mechanism to make SDK-provided journeys consistent with your app's visual identity and language.
What This Covers
- configuring the SDK color palette with
ThemeColorSet - understanding light and dark appearance behavior
- applying semantic text styles with
ThemeConfiguration - reusing
MobileIDThemecontrols in app-owned screens - adding brand imagery in custom integration screens
- translating or replacing SDK copy from the host app
- validating accessibility, formatting, and fallback behavior
API Surface
API | Purpose |
|---|---|
MobileIDConfiguration.colors | Supplies the palette applied when MobileID is created. |
ThemeColorSet | Defines primary, secondary, grayscale, status, and background colors. |
MIDColor | Creates SDK colors, including from six-digit RGB or eight-digit ARGB hex strings. |
ThemeConfiguration | Describes a color set and semantic UIKit text styles. |
ThemeConfiguration.colors(for:) | Resolves the palette for the current or specified appearance. |
ThemeColorSet.tint(for:tintColor:) | Chooses a contrasting foreground for a supplied background. |
ThemeManager.apply(_:) | Applies a theme through the SDK's UIKit appearance configuration. |
ThemeManager.updateNavigationBarAppearance(_:) | Refreshes navigation bar colors and typography. |
ThemeManager.updateTabBarAppearance(_:) | Refreshes tab bar colors. |
MIDLabel, MIDButton, MIDTextField, and related types | Reusable themed controls for app-owned or custom SDK screens. |
LocalizationFile and String.localized(_:) | Resolve localized strings from an app or framework bundle. |
Configure The Brand Palette
Create one palette and pass it to MobileIDConfiguration. The SDK applies it during MobileIDFactory.create(...), before SDK-provided screens are presented.
Swift1import MobileIDCore2import MobileIDTheme34extension ThemeColorSet {5 static let appBrand = ThemeColorSet(6 primary: MIDColor(hexString: "#1F3A8A"),7 secondary: MIDColor(hexString: "#2563EB"),8 grayscaleDark: MIDColor(hexString: "#0F172A"),9 grayscaleMediumDark: MIDColor(hexString: "#334155"),10 grayscaleMedium: MIDColor(hexString: "#64748B"),11 grayscaleLight: MIDColor(hexString: "#CBD5E1"),12 accentRed: MIDColor(hexString: "#DC2626"),13 accentOrange: MIDColor(hexString: "#EA580C"),14 accentGreen: MIDColor(hexString: "#16A34A"),15 background: MIDColor(hexString: "#FFFFFF")16 )17}1819let configuration = MobileIDConfiguration(20 appInfo: AppInfoConfiguration(projectId: "<PROJECT_ID>"),21 colors: .appBrand,22 enrollmentPlugins: [23 // Plugins enabled for your tenant.24 ],25 captureSDKConfiguration: nil,26 walletConfigurationTimeToLiveInMinutes: WalletDownloadConfiguration.twentyFourHoursInMinutes27)
MIDColor(hexString:) accepts RRGGBB and AARRGGBB, with or without #. Use eight digits only when an alpha channel is intentional.
Color Token Responsibilities
Token | Typical SDK usage |
|---|---|
primary | Primary brand emphasis, switches, selections, and some plain actions. |
secondary | Main buttons, links, navigation actions, and selected controls. |
grayscaleDark | Strong text and the dark-appearance background source. |
grayscaleMediumDark | Body and supporting text. |
grayscaleMedium | Muted or disabled content. |
grayscaleLight | Borders, fields, keypads, and subtle surfaces. |
accentRed | Error and destructive states. |
accentOrange | Warning states. |
accentGreen | Success states. |
background | Primary light-appearance surface. |
The same token may be used by several SDK controls. Treat each value as a design-system role rather than as a screen-specific color.
Light And Dark Appearance
The SDK derives its dark palette from the supplied light palette. It does not accept a second, independent dark ThemeColorSet through MobileIDConfiguration.
In dark appearance, the SDK:
- makes
primary,secondary, andaccentOrangemore vibrant, - uses white for
grayscaleDark, - swaps the light and medium-dark grayscale roles,
- uses the configured
grayscaleDarkas the background, - preserves the red, green, and medium grayscale tokens.
Test both appearances with real content. In particular, verify contrast for the secondary color against background, and for text against both background and grayscaleDark.
Semantic Typography
ThemeConfiguration maps SDK text roles to UIKit semantic styles. ThemeManager resolves those styles with UIFont.preferredFont(forTextStyle:), so Dynamic Type remains active.
Swift1import MobileIDTheme2import UIKit34struct AppTheme: ThemeConfiguration {5 let colors: ThemeColorSet67 let largeTitleStyle: UIFont.TextStyle = .largeTitle8 let titleStyle: UIFont.TextStyle = .title19 let title3Style: UIFont.TextStyle = .title310 let headlineStyle: UIFont.TextStyle = .headline11 let bodyStyle: UIFont.TextStyle = .body12 let calloutStyle: UIFont.TextStyle = .callout13 let footnoteStyle: UIFont.TextStyle = .footnote14}1516@MainActor17func applyAppTheme() {18 ThemeManager.apply(AppTheme(colors: .appBrand))19}
Call ThemeManager.apply(_:) on the main thread before creating the screens that should receive the appearance. Normal SDK initialization already applies the color set from MobileIDConfiguration; call it yourself only when you need a separate ThemeConfiguration, such as one shared with a custom screen or FaceConfiguration. When using a separate theme with MobileID, apply it after MobileIDFactory.create(...) finishes so SDK initialization does not replace it.
The theme protocol selects semantic text styles, not a custom font family. If your brand requires a specific typeface, use it in app-owned screens and verify any direct UIKit appearance customization against SDK updates and Dynamic Type.
Reuse SDK-Themed Controls
App-owned screens can use MobileIDTheme components to match SDK-provided journeys:
Swift1import MobileIDTheme23let titleLabel = MIDTitleLabel()4titleLabel.text = NSLocalizedString("enrollment.welcome.title", comment: "")56let continueButton = MIDPrimaryButton(frame: .zero)7continueButton.setTitle(8 NSLocalizedString("common.continue", comment: ""),9 for: .normal10)
Common reusable types include:
MIDLargeTitleLabel,MIDTitleLabel,MIDHeadlineLabel, andMIDLabelMIDPrimaryButton,MIDSecondaryButton, andMIDPlainButtonMIDTextField,MIDTextView,MIDSwitch, andMIDSegmentedControlMIDView,MIDErrorView, andMIDPopupView
These controls receive values from ThemeManager through UIKit appearance. Apply the theme before instantiating them.
Brand Images And Custom Screens
ThemeColorSet does not contain a logo, illustration, or icon slot. SDK-owned images are not replaced by adding assets with matching names to the host app.
Place brand imagery in app-owned screens instead. Enrollment provides EnrollmentInteractionDelegate.enrollmentView(for:) for supported custom interaction contexts, and authentication delegates let the app control how SDK view controllers are presented. Use the host app's asset catalog for logos and illustrations in those screens.
RequestData.clientMetadata.logoURL is request metadata supplied for a client application; it is not the SDK theme logo.
Localize SDK Copy
The SDK first looks in the host application's main bundle for a prefixed override. If no override exists, it reads the unprefixed key from the framework that owns the screen.
1. Add App Localizations
Create a Localizable.strings file for every supported app language and include it in the main application target. Override an SDK string by prefixing its key with com.idemia.mid..
For example, en.lproj/Localizable.strings:
Text1"com.idemia.mid.loc_continue" = "Next";2"com.idemia.mid.loc_enter_your_email" = "Enter your work email";3"com.idemia.mid.loc_photograph_results_retake" = "Take another photo";
And pl.lproj/Localizable.strings:
Text1"com.idemia.mid.loc_continue" = "Dalej";2"com.idemia.mid.loc_enter_your_email" = "Wpisz służbowy adres e-mail";3"com.idemia.mid.loc_photograph_results_retake" = "Zrób kolejne zdjęcie";
The SDK follows standard iOS bundle language selection; there is no SDK-specific language setter. The app's supported localizations and the user's system/app language determine which resource is loaded.
2. Find The Keys To Override
Use the English Localizable.strings files shipped in the installed SDK modules as the source list. Include only keys from modules linked by your app:
MobileIDCoreMobileIDThemeMobileIDCommonUtilsMobileIDEnrollmentPluginEmailBindingMobileIDEnrollmentPluginPhoneBindingMobileIDEnrollmentPluginFaceMatchingMobileIDEnrollmentPluginDocumentAuthentication
Copy the unprefixed loc_* key, add com.idemia.mid. in the app's strings file, and provide the localized value. Review the key list again when upgrading the SDK because journeys and copy can evolve.
3. Preserve Format Arguments
Some values contain format placeholders such as %@ or %d. Preserve the placeholder type and count in every translation. For example:
Text1"com.idemia.mid.loc_invalid_field" = "Invalid %@";
Do not translate localization keys, and do not add or remove format arguments. Validate every formatted string in a debug build because a mismatched placeholder can produce broken copy or a runtime failure.
4. Understand Shared Overrides
The override namespace is global to the host app. If more than one SDK module requests the same key, such as loc_continue, one prefixed app value overrides that key everywhere. Use shared wording for shared keys. Use custom app-owned screens when different journeys require different wording for the same SDK key.
5. Localize App-Owned Copy
Use standard Apple localization APIs for your own screens. MobileIDCommonUtils also exposes LocalizationFile and String.localized(_:) when an integration layer needs the same bundle-based lookup helper:
Swift1import MobileIDCommonUtils23let title = "enrollment_welcome_title".localized(.main)
For an unprefixed app-owned key, the helper falls back to the selected table in the supplied bundle.
Validation Checklist
- Initialize
MobileIDwith the production palette before presenting SDK UI. - Review every journey in light and dark appearances.
- Check normal, disabled, selected, warning, error, and success states.
- Test Dynamic Type through the largest supported accessibility sizes.
- Check VoiceOver labels after changing visible copy.
- Exercise every supported app language, including fallback to English.
- Verify text expansion, line wrapping, button height, and navigation titles.
- Test all
%@and%dsubstitutions with representative values. - Confirm shared keys such as
loc_continueread correctly in every module.
Troubleshooting
Symptom | Check |
|---|---|
| The default SDK text still appears | Confirm the key starts with com.idemia.mid., the strings file belongs to the main app target, and the active language has that entry. |
| A translation changes several screens | The modules share the same underlying loc_* key; a host override is global. |
| A color change does not affect an existing control | Apply the theme before creating the control, then recreate or refresh the screen. |
| Dark appearance has poor contrast | Review the automatically derived dark mapping, especially grayscaleDark, secondary, and background. |
| A formatted value is missing or malformed | Match every source placeholder and its type in the translated value. |
| A logo asset is ignored by an SDK screen | There is no global SDK logo override; put the asset in an app-owned/custom screen. |
Related Pages
Getting StartedEnrollment OrchestrationPIN And Liveness Verification