Modern applications allow users to personalize UI colors at runtime — without rebuilding the app or reloading the page. The best way to achieve this in Angular is by using CSS variables, real-time color pickers, and a theme service that writes styles directly to :root.
Below is a complete, practical, production-ready guide.
Architecture Overview (smaller header)
Angular App
|
|— ThemeService (writes CSS variables at runtime)
|
|— Theme Editor Component (color picker UI)
|
|— Global Styles (CSS variables in :root)
Workflow Diagram (smaller header)
User selects color →
Color Picker emits value →
ThemeService.setVar('--primary', value) →
CSS variable updates instantly →
All components using var(--primary) update live
ER Diagram (Optional – For Persisting Themes in DB)
(Skip if you don’t store themes on backend)
+----------------------+
| Theme |
+----------------------+
| ThemeId (PK) |
| UserId |
| PrimaryColor |
| SecondaryColor |
| BackgroundColor |
| AccentColor |
+----------------------+
Sequence Diagram (smaller header)
User → ThemeEditor: selects new color
ThemeEditor → ThemeService: setCssVariable('--primary', '#4caf50')
ThemeService → DOM: write variable to :root
DOM → UI Components: instantly reflect new color
Step-by-Step Practical Implementation (Frontend Only)
1. Define Global CSS Variables
Add to styles.css:
:root {
--primary: #1976d2;
--secondary: #424242;
--background: #ffffff;
--accent: #ff4081;
}
body {
background: var(--background);
color: var(--secondary);
}
.btn-primary {
background: var(--primary);
color: #fff;
}
2. Create ThemeService (writes variables live)
theme.service.ts
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ThemeService {
setVar(variable: string, value: string) {
document.documentElement.style.setProperty(variable, value);
}
getVar(variable: string): string {
return getComputedStyle(document.documentElement).getPropertyValue(variable);
}
// store theme in local storage
saveTheme(theme: Record<string, string>) {
localStorage.setItem('app-theme', JSON.stringify(theme));
}
loadTheme() {
const saved = localStorage.getItem('app-theme');
if (!saved) return;
const theme = JSON.parse(saved);
Object.keys(theme).forEach(v => this.setVar(v, theme[v]));
}
}
Load saved theme in your main component:
constructor(private theme: ThemeService) {
this.theme.loadTheme();
}
3. Create Color Picker Theme Editor
theme-editor.component.html
<div class="theme-editor">
<label>Primary Color</label>
<input type="color" [(ngModel)]="primary" (change)="update('--primary', primary)" />
<label>Secondary Color</label>
<input type="color" [(ngModel)]="secondary" (change)="update('--secondary', secondary)" />
<label>Background</label>
<input type="color" [(ngModel)]="background" (change)="update('--background', background)" />
<label>Accent</label>
<input type="color" [(ngModel)]="accent" (change)="update('--accent', accent)" />
<button (click)="save()">Save Theme</button>
</div>
theme-editor.component.ts
import { Component } from '@angular/core';
import { ThemeService } from '../theme.service';
@Component({
selector: 'app-theme-editor',
templateUrl: './theme-editor.component.html',
styleUrls: ['./theme-editor.component.css']
})
export class ThemeEditorComponent {
primary = '#1976d2';
secondary = '#424242';
background = '#ffffff';
accent = '#ff4081';
constructor(private theme: ThemeService) {}
update(variable: string, value: string) {
this.theme.setVar(variable, value);
}
save() {
this.theme.saveTheme({
'--primary': this.primary,
'--secondary': this.secondary,
'--background': this.background,
'--accent': this.accent
});
alert('Theme saved!');
}
}
4. Add Module & Routing
theme-editor.module.ts
@NgModule({
declarations: [ThemeEditorComponent],
imports: [
CommonModule,
FormsModule,
RouterModule.forChild([
{ path: '', component: ThemeEditorComponent }
])
]
})
export class ThemeEditorModule {}
Add lazy route in app-routing.module.ts:
{
path: 'theme-editor',
loadChildren: () => import('./theme-editor/theme-editor.module')
.then(m => m.ThemeEditorModule)
}
5. Use CSS variables inside Angular components
Example: button.component.css
button {
background: var(--primary);
border: none;
color: #fff;
padding: 10px 20px;
}
The component automatically updates when user changes the theme.
Advanced Features (Optional)
Live Theme Preview
Theme Export / Import
Server Persistence
Store theme using API:
POST /api/theme/save
GET /api/theme/user/{id}