Angular  

Creating Theme Runtime Editing in Angular (Color Picker → Writes CSS Variables Live, No Page Reload)

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

  • Show a preview card with updated CSS variables.

Theme Export / Import

  • Allow users to export theme JSON.

  • Allow import → load into UI → apply via ThemeService.

Server Persistence

Store theme using API:

POST /api/theme/save
GET /api/theme/user/{id}