Introduction
In enterprise software, user interface (UI) design is not just about good looks — it’s about adaptability, consistency, and flexibility. Large organizations often have multiple brands, regional clients, or departments that require their own color schemes, logos, and typography, all under a single unified application.
To achieve this, developers need a multi-theme architecture that allows brand customization without rebuilding or redeploying the app.
In this guide, we’ll go step-by-step through building a multi-theme and brand customization system using Angular (frontend) and ASP.NET Core (backend) — ideal for enterprise-scale products.
Why Multi-Theming is Essential in Enterprise UIs
Enterprises typically manage:
Multiple client-specific branding requirements
White-labeled portals (same app, different visuals)
Regional or accessibility-based color preferences
Dark/Light mode for modern UX
Manually maintaining separate codebases for each theme is inefficient. Instead, a centralized theming system ensures:
Quick rollout of new themes or clients
Consistent UX across modules
Dynamic runtime theme switching
Easier maintainability and testing
The Importance of Theming and Branding
A scalable enterprise app needs both functional theming (colors, layout, icons) and brand theming (logos, fonts, identity).
| Type | Purpose | Example |
|---|
| Functional Theme | User preference or accessibility | Dark/Light Mode |
| Brand Theme | Client-specific identity | “Brand A” uses blue, “Brand B” uses red |
A good system separates core layout logic from theme presentation, ensuring that adding a new brand is just configuration — not new development.
Common Enterprise Requirements
Dynamic Light/Dark Mode Switching
Users can toggle between modes without page reload.
Multiple Brand Palettes
Each client gets unique color, logo, and font.
Runtime Theme Loading
Theme data fetched from backend during login or context change.
Brand Assets from API
Logos, favicons, and accent colors loaded dynamically from an ASP.NET Core API.
Accessibility Compliance
All color contrasts meet WCAG 2.1 AA standards.
Architecture Overview
The high-level architecture of a multi-theme enterprise app looks like this:
+---------------------------------------------------+
| User Interface (Angular) |
|---------------------------------------------------|
| - Theme Service |
| - CSS Variables / SCSS Mixins |
| - Angular Material Palette |
+---------------------------------------------------+
| API Layer (ASP.NET Core) |
|---------------------------------------------------|
| - Brand Configuration Controller |
| - Fetch theme colors, fonts, logo URLs |
| - Serve JSON responses |
+---------------------------------------------------+
| Database Layer |
|---------------------------------------------------|
| - Brand table: BrandId, PrimaryColor, Font, Logo |
+---------------------------------------------------+
Technical Flowchart: Theme Customization Workflow
┌─────────────────────┐
│ User Logs In │
└────────┬────────────┘
│
▼
┌──────────────────────────┐
│ ASP.NET Core API loads │
│ brand/theme info from DB│
└────────┬─────────────────┘
│ (returns JSON)
▼
┌──────────────────────────┐
│ Angular loads Theme JSON │
│ via ThemeService │
└────────┬─────────────────┘
│
▼
┌──────────────────────────┐
│ CSS variables + logo set │
│ dynamically via renderer │
└──────────────────────────┘
Implementation Approaches in Angular
There are multiple ways to implement dynamic theming in Angular:
Using CSS Variables (Recommended for modern Angular)
Using SCSS Mixins with Angular Material Palettes
Dynamic Class Injection (for older browsers)
Let’s explore a practical implementation.
Step 1: Define CSS Variables
In styles.scss:
:root {
--primary-color: #0078d7;
--secondary-color: #2b2b2b;
--text-color: #222;
}
[data-theme="dark"] {
--primary-color: #1e88e5;
--secondary-color: #121212;
--text-color: #fff;
}
Use these variables in components:
button {
background-color: var(--primary-color);
color: var(--text-color);
}
Step 2: Angular Theme Service
Create a service to manage themes dynamically.
import { Injectable, Renderer2, RendererFactory2 } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ThemeService {
private renderer: Renderer2;
private currentTheme = 'light';
constructor(rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
}
setTheme(theme: string) {
this.currentTheme = theme;
this.renderer.setAttribute(document.body, 'data-theme', theme);
}
getTheme() {
return this.currentTheme;
}
}
Switching theme:
this.themeService.setTheme('dark');
Step 3: Load Brand Config from ASP.NET Core API
Backend (ASP.NET Core)
Model
public class BrandTheme
{
public string BrandId { get; set; } = string.Empty;
public string PrimaryColor { get; set; } = "#0078d7";
public string SecondaryColor { get; set; } = "#2b2b2b";
public string LogoUrl { get; set; } = string.Empty;
public string FontFamily { get; set; } = "Roboto, sans-serif";
}
Controller
[ApiController]
[Route("api/[controller]")]
public class BrandController : ControllerBase
{
[HttpGet("{brandId}")]
public IActionResult GetBrandTheme(string brandId)
{
var theme = new BrandTheme
{
BrandId = brandId,
PrimaryColor = "#1a73e8",
SecondaryColor = "#f5f5f5",
LogoUrl = "/assets/brandA-logo.png",
FontFamily = "Poppins, sans-serif"
};
return Ok(theme);
}
}
Frontend (Angular)
Service
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class BrandService {
constructor(private http: HttpClient) {}
getBrandConfig(brandId: string) {
return this.http.get(`/api/brand/${brandId}`);
}
}
Applying Brand at Runtime
this.brandService.getBrandConfig('BrandA').subscribe((config: any) => {
document.documentElement.style.setProperty('--primary-color', config.primaryColor);
document.documentElement.style.setProperty('--secondary-color', config.secondaryColor);
document.body.style.fontFamily = config.fontFamily;
});
Step 4: Multiple Themes in Angular Material
Angular Material supports custom palettes.
theme.scss
@use '@angular/material' as mat;
$light-primary: mat.define-palette(mat.$indigo-palette, 500);
$light-accent: mat.define-palette(mat.$pink-palette, A200);
$dark-primary: mat.define-palette(mat.$blue-grey-palette, 700);
$dark-accent: mat.define-palette(mat.$deep-orange-palette, A200);
$light-theme: mat.define-light-theme((
color: (primary: $light-primary, accent: $light-accent)
));
$dark-theme: mat.define-dark-theme((
color: (primary: $dark-primary, accent: $dark-accent)
));
Switch dynamically
this.themeService.setTheme('dark');
Step 5: Storing Brand Info in Database
Table: BrandTheme
| BrandId | PrimaryColor | SecondaryColor | LogoUrl | FontFamily |
|---|
| BrandA | #1a73e8 | #f5f5f5 | /assets/brandA.png | Poppins |
| BrandB | #00695c | #ffffff | /assets/brandB.png | Open Sans |
You can expose an API to update these values from an admin panel — enabling runtime brand configuration without code changes.
Step 6: Accessibility and WCAG Compliance
Each theme must follow WCAG 2.1 AA guidelines.
Test for:
Tools like axe, Lighthouse, and Accessibility Insights can automate A11y testing.
Step 7: Performance Optimization
Avoid multiple CSS bundles — use CSS variables instead.
Load logos and assets on demand.
Cache brand configuration in localStorage or service worker.
Preload default theme during Angular app initialization.
Example
APP_INITIALIZER: {
provide: APP_INITIALIZER,
useFactory: (brandService: BrandService) => () => brandService.loadDefaultTheme(),
deps: [BrandService],
multi: true
}
Step 8: Deployment and Maintenance
Deploy static assets per brand in a CDN folder (e.g., /brandA/, /brandB/).
Version theme configurations to track updates.
Use CI/CD pipeline to promote new themes safely.
Example (Jenkins/GitHub Actions):
Step 1: Build Angular app
Step 2: Copy brand assets
Step 3: Deploy to environment with theme configuration
Conclusion
Multi-theme and brand customization are critical capabilities for any enterprise-grade web application.
With the right approach, developers can:
Serve multiple clients under one codebase
Switch themes dynamically at runtime
Maintain brand consistency effortlessly
Support accessibility and dark mode
By combining Angular’s modern theming tools with ASP.NET Core’s configuration APIs, you can build a scalable and future-ready UI system that adapts to every client’s identity — all without sacrificing performance or maintainability.