Theme System Usage Guide
Complete guide for using our theme system effectively - the right way to implement themes in components
Theme System Usage Guide
🎯 Quick Start - The Right Way
Our theme system is designed to be simple and powerful. No wrapper services needed - use the theme system directly!
✅ Simple Component Usage
import { Component, inject, computed } from '@angular/core';
import { ThemeManagerService, ThemeMode } from '@theme-runtime';
@Component({
selector: 'app-my-component',
template: `
<div class="themed-component">
<h2>{{ themeName() }}</h2>
<button (click)="toggleMode()">Toggle Mode</button>
</div>
`,
styles: [`
.themed-component {
background-color: var(--ux-surface);
color: var(--ux-on-surface);
padding: var(--ux-space-md);
border-radius: var(--ux-radius-md);
}
`]
})
export class MyComponent {
private themeManager = inject(ThemeManagerService);
themeName = computed(() => this.themeManager.activeTheme()?.metadata?.name || 'Default');
async toggleMode() {
const current = this.themeManager.activeTheme()?.mode;
const newMode = current === ThemeMode.LIGHT ? ThemeMode.DARK : ThemeMode.LIGHT;
await this.themeManager.setThemeMode(newMode);
}
}
✅ CSS Variables - Use Directly
.my-component {
// ✅ Use CSS variables directly - they update automatically
background-color: var(--ux-primary);
color: var(--ux-on-primary);
border: 1px solid var(--ux-border);
border-radius: var(--ux-radius-md);
padding: var(--ux-space-md);
// ✅ Transitions work automatically
transition: all var(--ux-transition-medium);
&:hover {
background-color: var(--ux-primary-dark);
box-shadow: var(--ux-shadow-sm);
}
}
🚫 What NOT to Do
❌ Don't Create Wrapper Services
// ❌ DON'T DO THIS
@Injectable()
export class UnnecessaryThemeWrapper {
private themeManager = inject(ThemeManagerService);
// This just duplicates existing functionality!
getTheme() {
return this.themeManager.activeTheme();
}
}
❌ Don't Use Dynamic Imports for Core Services
// ❌ DON'T DO THIS
async loadThemeManager() {
const themeSystem = await import('@theme-runtime');
return this.injector.get(themeSystem.ThemeManagerService);
}
❌ Don't Manually Cache Theme Data
// ❌ DON'T DO THIS - The theme system handles caching
private cachedTheme: Theme | null = null;
getTheme() {
if (!this.cachedTheme) {
this.cachedTheme = this.themeManager.activeTheme();
}
return this.cachedTheme;
}
📋 Available CSS Variables
Our theme system provides these CSS variables automatically:
Colors
--ux-primary,--ux-primary-light,--ux-primary-dark--ux-secondary,--ux-secondary-light,--ux-secondary-dark--ux-tertiary,--ux-tertiary-light,--ux-tertiary-dark--ux-background,--ux-surface,--ux-border--ux-on-primary,--ux-on-secondary,--ux-on-surface--ux-error,--ux-warning,--ux-success,--ux-info
Spacing
--ux-space-xs,--ux-space-sm,--ux-space-md,--ux-space-lg,--ux-space-xl
Border Radius
--ux-radius-xs,--ux-radius-sm,--ux-radius-md,--ux-radius-lg,--ux-radius-xl
Shadows
--ux-shadow-sm,--ux-shadow-md,--ux-shadow-lg,--ux-shadow-xl
Typography
--ux-font-family-base,--ux-font-size-*,--ux-font-weight-*
Transitions
--ux-transition-fast,--ux-transition-medium,--ux-transition-slow
🎯 When to Create a Service
Only create a theme-related service if you have:
- Complex business logic that needs to be shared across components
- Data transformation or processing requirements
- Integration with external systems
- Stateful operations that need coordination
✅ Example: When a Service Makes Sense
@Injectable({
providedIn: 'root'
})
export class CustomThemeBusinessLogicService {
private readonly themeManager = inject(ThemeManagerService);
/**
* ✅ EXAMPLE: Custom business logic that justifies a service
* Calculate accessibility contrast ratios for the current theme
*/
getAccessibilityReport(): Observable<AccessibilityReport> {
return this.themeManager.themeChanged$.pipe(
map(theme => this.calculateAccessibilityReport(theme)),
distinctUntilChanged()
);
}
/**
* ✅ EXAMPLE: Complex theme transformation
* Generate a complementary theme based on current theme
*/
async generateComplementaryTheme(): Promise<Theme> {
const currentTheme = this.themeManager.activeTheme();
// Complex business logic here...
return transformedTheme;
}
}
🔧 Available Services
Core Services (Use These Directly)
ThemeManagerService- Main theme orchestrationThemeApplicationService- Apply themes to DOMThemeStorageService- Theme persistenceThemeGeneratorService- Generate new themesAIThemeGeneratorService- AI-powered theme generation
Utility Services
ThemeLoggerService- Logging and debuggingThemeCleanupService- Storage cleanupThemeUtilitiesService- Helper utilities
🚀 Performance Tips
- Use CSS variables instead of JavaScript for styling
- Use computed signals for reactive theme data
- Avoid unnecessary service layers
- Let the theme system handle caching and updates
- Use the built-in reactivity instead of manual subscriptions
🛠️ Advanced Patterns
Reactive Theme Data
export class AdvancedThemeComponent {
private themeManager = inject(ThemeManagerService);
// ✅ Reactive theme properties
currentTheme = computed(() => this.themeManager.activeTheme());
isDarkMode = computed(() => this.currentTheme()?.mode === ThemeMode.DARK);
primaryColor = computed(() => this.currentTheme()?.colors?.primary || '#4f46e5');
// ✅ Listen to theme changes
themeChanges$ = this.themeManager.themeChanged$;
}
Utility Functions
/**
* Get a theme color with fallback
*/
export function getThemeColor(colorKey: string, fallback = '#000000'): string {
return getComputedStyle(document.documentElement)
.getPropertyValue(`--ux-${colorKey}`)
.trim() || fallback;
}
/**
* Check if current theme is dark mode
*/
export function isDarkMode(): boolean {
return document.documentElement.getAttribute('data-theme-mode') === 'dark';
}
🆘 Troubleshooting
Theme not updating?
- Ensure you're using CSS variables:
var(--ux-primary) - Check that the theme system is properly initialized in
app.config.ts
TypeScript errors?
- Import types from
@theme-runtime - Use
inject()for dependency injection
Performance issues?
- Avoid wrapper services
- Use computed signals instead of manual subscriptions
- Let CSS handle styling with variables
📚 Best Practices Summary
✅ DO THIS:
- Use direct injection:
inject(ThemeManagerService) - Use computed signals for reactive theme data
- Use CSS variables directly in styles:
var(--ux-primary) - Keep components simple and focused
- Use the theme system's built-in reactivity
- Handle errors gracefully in async operations
🚫 AVOID:
- Wrapper services
- Dynamic imports for core services
- Manual theme caching
- Complex abstraction layers
- Duplicating existing functionality
This guide ensures you use our theme system effectively and maintainably. Follow these patterns for consistent, performant theme integration.