Without a Theming Engine, every design change in a white-label app requires a rebuild and release. One of our clients was spending 72 man-hours per month updating themes for 15 brands. After implementing a Theming Engine, that task shrank to one hour: just upload a new JSON config to the server. Result: 98% time savings and full flexibility. We have 6+ years of experience in white-label development and have delivered over 30 projects with dynamic theming. If you need to flexibly manage the appearance of dozens of brands, contact us — we will propose a solution.
How Does a Theming Engine Improve White-Label Apps?
A Theming Engine is a system that manages visual parameters of an app through design tokens. All colors, fonts, sizes, corner radii, and shadows are externalized into a JSON config that is loaded at startup or switched at runtime. This enables runtime theme switching without rebuild, supports hundreds of brands in a single build, and adapts the interface to user preferences. A single configuration for all brands simplifies maintenance.
Config Structure (Example for Tenant "Brand B")
{ "tenant": "brand_b", "version": "2", "colors": { "primary": "#1A73E8", "primary_variant": "#1557B0", "secondary": "#FB8C00", "background": "#FFFFFF", "surface": "#F5F5F5", "error": "#B00020", "on_primary": "#FFFFFF", "on_secondary": "#000000" }, "typography": { "font_family": "Inter", "scale_factor": 1.0 }, "shape": { "card_corner_radius": 12, "button_corner_radius": 8, "input_corner_radius": 4 }, "assets": { "logo_url": "https://cdn.brand-b.com/logo.png", "splash_bg_color": "#1A73E8" } } Static vs Dynamic Approach Comparison
| Criteria | Static Theme (xcconfig/flavors) | Dynamic Theme (Theming Engine) |
|---|---|---|
| Theme change without release | No | Yes |
| Number of tenants | Up to 10 | Unlimited |
| Runtime theme switching support | No | Yes |
| Implementation complexity | Low | Medium |
| Design flexibility | Limited | High |
Estimated Implementation Time by Platform
| Platform | New Project | Refactoring Existing |
|---|---|---|
| iOS (SwiftUI) | 2 weeks | 3–5 weeks |
| Android (Compose) | 2 weeks | 3–5 weeks |
| Flutter | 3 weeks | 4–6 weeks |
| React Native | 3 weeks | 4–6 weeks |
How to Implement Dynamic Theme in Jetpack Compose?
Jetpack Compose makes dynamic theming significantly easier than XML: MaterialTheme accepts ColorScheme and Typography as parameters and applies them to the entire component tree.
// Loading and parsing the theme in Compose @Composable fun TenantThemedApp(theme: TenantTheme, content: @Composable () -> Unit) { val colorScheme = lightColorScheme( primary = Color(android.graphics.Color.parseColor(theme.colors.primary)), primaryContainer = Color(android.graphics.Color.parseColor(theme.colors.primaryVariant)), secondary = Color(android.graphics.Color.parseColor(theme.colors.secondary)), background = Color(android.graphics.Color.parseColor(theme.colors.background)), surface = Color(android.graphics.Color.parseColor(theme.colors.surface)), error = Color(android.graphics.Color.parseColor(theme.colors.error)) ) val shapes = Shapes( small = RoundedCornerShape(theme.shapes.inputCornerRadius.dp), medium = RoundedCornerShape(theme.shapes.cardCornerRadius.dp), large = RoundedCornerShape(theme.shapes.buttonCornerRadius.dp) ) MaterialTheme(colorScheme = colorScheme, shapes = shapes, content = content) } // Usage in Activity setContent { val theme by themeViewModel.tenantTheme.collectAsState() TenantThemedApp(theme = theme) { AppNavHost() } } When tenantTheme changes in the ViewModel, the entire UI redraws automatically. Runtime font loading is done via the Downloadable Fonts API; fonts are cached after the first load, eliminating startup delays. In practice, a theme switch takes less than 2 seconds, whereas a static release takes 24 hours.
Flutter and React Native
Flutter: ThemeData in MaterialApp is parameterized similarly to Compose. For full control, use InheritedWidget or a Riverpod provider with the theme object. Runtime font loading via the FontLoader API.
React Native: ThemeContext via React Context API; StyleSheet.create is called with tokens from the context. Hot-reloading the theme without restart is achieved via useContext(ThemeContext) in components.
Why is the Stale-While-Revalidate Pattern Important for Theme Loading?
Stale-while-revalidate (described in MDN documentation) is a caching strategy that guarantees data freshness without delays. Show the cached theme immediately, update in the background. This eliminates waiting at startup and prevents broken UI on network errors.
class ThemeStore: ObservableObject { @Published var currentTheme: TenantTheme = .default func loadTheme(tenantId: String) async { do { if let cached = ThemeCache.load(tenantId: tenantId) { await MainActor.run { currentTheme = cached } } let dto = try await api.fetchTheme(tenantId: tenantId) let theme = TenantTheme(from: dto) ThemeCache.save(theme, tenantId: tenantId) await MainActor.run { currentTheme = theme } } catch { // Fallback to default theme, do not crash } } } Standard loading without this pattern would result in an empty screen for 200–300 ms. Compare: a static theme takes 24 hours for release, a dynamic one switches in 2 seconds — a 43,200x difference.
How Does Theme Versioning Prevent Broken UI?
When the contract is updated (a new token is added), older cached themes may lack that field. If the theme version is below the minimum supported version, we use a bundled default theme. This protects against displaying broken UI.
Process of Work
- UI audit: inventory all colors, fonts, radii in the app, identify hardcoded values.
- Token schema design together with the designer: which parameters differ between brands.
- Implement ThemeProvider, environment-based application, loading from API.
- Refactor components: replace hardcoded values with tokens, cover with visual tests (Paparazzi for Android, SwiftUI Previews for iOS).
- Test runtime theme switching: all components redraw correctly, fonts load without flickering.
Timeline Estimates
A Theming Engine for a new app from scratch (Compose or SwiftUI) — 2–3 weeks. Refactoring an existing app with hardcoded colors — depends on codebase size, typically 3–6 weeks. Cost is calculated individually.
Theming Engine Implementation Checklist
- UI audit: inventory all colors, fonts, radii
- Design token schema with designer
- Implement ThemeProvider and theme loader
- Refactor components: replace hardcoded values with tokens
- Configure caching and error handling
- Test theme switching: all components redraw correctly
- Document adding new tenants
Ready to implement a Theming Engine in your white-label app? Get expert consultation — we will analyze your UI and propose the optimal solution.







