In today's multi-brand landscape, it's common for applications to support multiple brands, each with its unique look and feel. Angular, with its powerful theming capabilities, makes it easy to create and manage themes for different brands. Whether you're using Angular Material or custom CSS, this guide will walk you through the process of creating and switching themes dynamically—even based on URL parameters!
Why Theming Matters
Theming allows you to:
- Maintain brand consistency across different platforms.
- Enhance user experience by providing a visually appealing interface.
- Simplify customization for different clients or brands.
In this blog post, we'll explore how to create and manage themes for multiple brands in an Angular application, including how to dynamically load themes based on URL parameters.
Step 1: Set Up Angular Material (Optional)
If you're using Angular Material, it provides a robust theming system. To get started, install Angular Material:
ng add @angular/material
This will set up Angular Material and its theming system in your project.
Step 2: Define Theme Variables
Create separate SCSS files for each brand's theme. For example:
Brand 1 Theme
// src/styles/themes/_brand1.scss
@use '@angular/material' as mat;
$brand1-primary: mat.define-palette(mat.$indigo-palette);
$brand1-accent: mat.define-palette(mat.$pink-palette);
$brand1-warn: mat.define-palette(mat.$red-palette);
$brand1-theme: mat.define-light-theme((
color: (
primary: $brand1-primary,
accent: $brand1-accent,
warn: $brand1-warn,
)
));
// Apply the theme
@include mat.all-component-themes($brand1-theme);
Brand 2 Theme
// src/styles/themes/_brand2.scss
@use '@angular/material' as mat;
$brand2-primary: mat.define-palette(mat.$blue-palette);
$brand2-accent: mat.define-palette(mat.$amber-palette);
$brand2-warn: mat.define-palette(mat.$deep-orange-palette);
$brand2-theme: mat.define-dark-theme((
color: (
primary: $brand2-primary,
accent: $brand2-accent,
warn: $brand2-warn,
)
));
// Apply the theme
@include mat.all-component-themes($brand2-theme);
Step 3: Load Themes Dynamically
To switch between themes dynamically, you can use Angular's :host-context or a class-based approach.
Option 1: Using :host-context
Wrap your theme styles in :host-context:
// src/styles/themes/_brand1.scss
:host-context(.brand1) {
@include mat.all-component-themes($brand1-theme);
}
// src/styles/themes/_brand2.scss
:host-context(.brand2) {
@include mat.all-component-themes($brand2-theme);
}
Option 2: Using a Class-Based Approach
Add a class to the body element to switch themes:
// src/styles/themes/_brand1.scss
.brand1 {
@include mat.all-component-themes($brand1-theme);
}
// src/styles/themes/_brand2.scss
.brand2 {
@include mat.all-component-themes($brand2-theme);
}
Step 4: Switch Themes Based on URL Parameter
To dynamically load themes based on a URL parameter, we'll create a custom hook using Angular's ActivatedRoute and ThemeService.
Theme Service
First, create a ThemeService to manage the active theme:
// src/app/services/theme.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class ThemeService {
private activeTheme: string = 'brand1';
setTheme(theme: string): void {
this.activeTheme = theme;
document.body.className = theme;
}
getTheme(): string {
return this.activeTheme;
}
}
Custom Hook to Get Brand from URL
Create a custom hook (or utility function) to extract the brand from the URL parameter:
// src/app/utils/get-brand-from-url.ts
import { ActivatedRoute } from '@angular/router';
import { ThemeService } from '../services/theme.service';
export function getBrandFromUrl(route: ActivatedRoute, themeService: ThemeService): void {
route.queryParams.subscribe(params => {
const brand = params['brand'] || 'brand1'; // Default to 'brand1' if no parameter is provided
themeService.setTheme(brand);
});
}
Use the Hook in Your Component
Inject the ActivatedRoute and ThemeService into your component and use the custom hook:
// src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ThemeService } from './services/theme.service';
import { getBrandFromUrl } from './utils/get-brand-from-url';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private themeService: ThemeService
) {}
ngOnInit(): void {
// Use the custom hook to get the brand from the URL
getBrandFromUrl(this.route, this.themeService);
}
}
Step 5: Include Themes in Your Application
Import the theme files in your global styles (styles.scss):
// src/styles/styles.scss
@import './themes/brand1';
@import './themes/brand2';
Step 6: Custom CSS Themes (Non-Material)
If you're not using Angular Material, you can define custom CSS variables for each brand:
// src/styles/themes/_brand1.scss
:root.brand1 {
--primary-color: #3f51b5;
--accent-color: #e91e63;
--warn-color: #f44336;
}
// src/styles/themes/_brand2.scss
:root.brand2 {
--primary-color: #2196f3;
--accent-color: #ffc107;
--warn-color: #ff5722;
}
Use these variables in your components:
// src/app/app.component.scss
button {
background-color: var(--primary-color);
color: white;
}
Step 7: Testing and Validation
- Test your application with each theme to ensure consistency.
- Use tools like Storybook to visualize components with different themes.
Example URL
To test your application, navigate to:
- http://localhost:4200?brand=brand1 for Brand 1 theme.
- http://localhost:4200?brand=brand2 for Brand 2 theme.
Conclusion
Creating themes for different brands in Angular is a powerful way to maintain brand consistency and enhance user experience. By leveraging Angular Material or custom CSS, you can easily define and switch themes dynamically—even based on URL parameters. Whether you're building a multi-brand application or customizing for different clients, this approach is scalable and maintainable.
Start implementing themes in your Angular application today and take your UI customization to the next level!