Dynamic Theme Management
Learn to create and switch between themes dynamically at runtime.
Basic Theme System
Create a simple theme manager:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class ThemeManager {
private static currentTheme: "light" | "dark" = "light";
static themes = {
light: {
backgroundColor: "#ffffff",
color: "#000000",
borderColor: "#e0e0e0",
accentColor: "#0066cc"
},
dark: {
backgroundColor: "#1e1e1e",
color: "#ffffff",
borderColor: "#444444",
accentColor: "#66b3ff"
}
};
static setTheme(theme: "light" | "dark") {
this.currentTheme = theme;
const colors = this.themes[theme];
// Apply to document root
const style = new InlineStyle({
"--bg-color": colors.backgroundColor,
"--text-color": colors.color,
"--border-color": colors.borderColor,
"--accent-color": colors.accentColor
} as any);
style.applyTo(document.documentElement);
}
static getTheme() {
return this.currentTheme;
}
}
// Usage
ThemeManager.setTheme("dark");Live demo of theme switching:
Console
No logs yet.
Multi-Color Theme Palette
Define comprehensive color palettes:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class ColorPalette {
static palettes = {
ocean: {
primary: "#0077be",
secondary: "#00d4ff",
success: "#06a77d",
warning: "#ffc857",
error: "#d62828",
neutral: "#f5f5f5"
},
forest: {
primary: "#2d6a4f",
secondary: "#40916c",
success: "#52b788",
warning: "#d4a574",
error: "#a4243b",
neutral: "#f1faee"
},
sunset: {
primary: "#e76f51",
secondary: "#f4a261",
success: "#2a9d8f",
warning: "#f4a261",
error: "#d62828",
neutral: "#fffcf2"
}
};
static applyPalette(paletteKey: keyof typeof this.palettes) {
const palette = this.palettes[paletteKey];
// Create CSS custom properties
const vars: Record<string, string> = {};
Object.entries(palette).forEach(([key, value]) => {
vars[`--color-${key}`] = value;
});
new InlineStyle(vars as any).applyTo(document.documentElement);
}
}
// Usage
ColorPalette.applyPalette("ocean");Component-Level Theming
Apply themes to specific components:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class ComponentTheme {
static getButtonStyle(variant: "primary" | "secondary" | "danger") {
const variants = {
primary: {
backgroundColor: "#0066cc",
color: "#ffffff",
borderColor: "#0052a3"
},
secondary: {
backgroundColor: "#f0f0f0",
color: "#333333",
borderColor: "#cccccc"
},
danger: {
backgroundColor: "#dc3545",
color: "#ffffff",
borderColor: "#c82333"
}
};
return new InlineStyle({
padding: "10px 20px",
border: "1px solid",
borderRadius: "4px",
cursor: "pointer",
fontSize: "14px",
fontWeight: "500",
transition: "all 0.2s ease",
...variants[variant]
});
}
static applyButtonTheme(button: HTMLElement, variant: "primary" | "secondary" | "danger") {
this.getButtonStyle(variant).applyTo(button);
// Add hover effect
button.addEventListener("mouseenter", () => {
const variants = {
primary: { backgroundColor: "#0052a3" },
secondary: { backgroundColor: "#e0e0e0" },
danger: { backgroundColor: "#c82333" }
};
new InlineStyle({
...variants[variant],
transform: "translateY(-2px)",
boxShadow: "0 4px 12px rgba(0,0,0,0.15)"
}).applyTo(button);
});
button.addEventListener("mouseleave", () => {
this.getButtonStyle(variant).applyTo(button);
});
}
}
// Usage
document.querySelectorAll(".btn-primary").forEach(btn => {
if (btn instanceof HTMLElement) {
ComponentTheme.applyButtonTheme(btn, "primary");
}
});System Preference Detection
Respect user's system theme preference:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class SystemTheme {
static getSystemTheme(): "light" | "dark" {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
static applySystemTheme() {
const theme = this.getSystemTheme();
const themes = {
light: {
backgroundColor: "#ffffff",
color: "#000000"
},
dark: {
backgroundColor: "#121212",
color: "#ffffff"
}
};
new InlineStyle(themes[theme]).applyTo(document.body);
// Listen for system changes
window.matchMedia("(prefers-color-scheme: dark)").addListener((e) => {
const newTheme = e.matches ? "dark" : "light";
new InlineStyle(themes[newTheme]).applyTo(document.body);
});
}
}
// Usage
SystemTheme.applySystemTheme();LocalStorage Theme Persistence
Save user's theme preference:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class PersistentTheme {
private static STORAGE_KEY = "app-theme";
static getStoredTheme(): "light" | "dark" {
const stored = localStorage.getItem(this.STORAGE_KEY);
return (stored as "light" | "dark") || "light";
}
static saveTheme(theme: "light" | "dark") {
localStorage.setItem(this.STORAGE_KEY, theme);
}
static applyStoredTheme() {
const theme = this.getStoredTheme();
this.applyTheme(theme);
}
static applyTheme(theme: "light" | "dark") {
const styles = {
light: { backgroundColor: "#ffffff", color: "#000000" },
dark: { backgroundColor: "#1e1e1e", color: "#ffffff" }
};
new InlineStyle(styles[theme]).applyTo(document.body);
}
static toggleTheme() {
const current = this.getStoredTheme();
const next = current === "light" ? "dark" : "light";
this.applyTheme(next);
this.saveTheme(next);
}
}
// Initialize on page load
document.addEventListener("DOMContentLoaded", () => {
PersistentTheme.applyStoredTheme();
// Toggle button listener
document.querySelector(".theme-toggle")?.addEventListener("click", () => {
PersistentTheme.toggleTheme();
});
});Animated Theme Transitions
Smoothly transition between themes:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class AnimatedTheme {
static transitionDuration = 300; // milliseconds
static applyThemeWithAnimation(theme: "light" | "dark") {
const element = document.documentElement;
// Add transition
new InlineStyle({
transition: `background-color ${this.transitionDuration}ms ease, color ${this.transitionDuration}ms ease`
}).applyTo(element);
// Apply theme
const themes = {
light: { backgroundColor: "#ffffff", color: "#000000" },
dark: { backgroundColor: "#1e1e1e", color: "#ffffff" }
};
new InlineStyle(themes[theme]).applyTo(element);
// Remove transition after completion
setTimeout(() => {
new InlineStyle({
transition: "none"
}).applyTo(element);
}, this.transitionDuration);
}
}
// Usage
document.querySelector(".theme-btn")?.addEventListener("click", () => {
AnimatedTheme.applyThemeWithAnimation("dark");
});Context-Based Theming
Different themes for different sections:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class RegionalThemes {
static themes = {
marketing: {
primary: "#ff6b6b",
background: "#fff5f5",
text: "#1a1a1a"
},
dashboard: {
primary: "#0066cc",
background: "#f5f5f5",
text: "#000000"
},
admin: {
primary: "#2d3436",
background: "#2f3542",
text: "#ffffff"
}
};
static applyRegionalTheme(
section: HTMLElement,
themeKey: keyof typeof this.themes
) {
const theme = this.themes[themeKey];
new InlineStyle({
"--primary-color": theme.primary,
"--bg-color": theme.background,
"--text-color": theme.text
} as any).applyTo(section);
}
}
// Usage
const marketingSection = document.querySelector(".marketing-section");
const dashboardSection = document.querySelector(".dashboard-section");
if (marketingSection instanceof HTMLElement) {
RegionalThemes.applyRegionalTheme(marketingSection, "marketing");
}
if (dashboardSection instanceof HTMLElement) {
RegionalThemes.applyRegionalTheme(dashboardSection, "dashboard");
}Advanced Theme Composition
Combine and override themes:
typescript
import { InlineStyle } from "@briklab/lib/stylesheet";
class ComposedTheme {
static baseTheme = {
fontSize: "16px",
lineHeight: "1.5",
borderRadius: "4px"
};
static colorThemes = {
light: {
backgroundColor: "#ffffff",
color: "#000000"
},
dark: {
backgroundColor: "#1e1e1e",
color: "#ffffff"
}
};
static densityThemes = {
comfortable: { padding: "16px", gap: "12px" },
compact: { padding: "8px", gap: "6px" }
};
static getComposedTheme(
colorTheme: "light" | "dark",
densityTheme: "comfortable" | "compact"
) {
return new InlineStyle({
...this.baseTheme,
...this.colorThemes[colorTheme],
...this.densityThemes[densityTheme]
});
}
static applyComposedTheme(
element: HTMLElement,
colorTheme: "light" | "dark",
densityTheme: "comfortable" | "compact"
) {
this.getComposedTheme(colorTheme, densityTheme).applyTo(element);
}
}
// Usage
const layout = document.querySelector(".app-layout");
if (layout instanceof HTMLElement) {
ComposedTheme.applyComposedTheme(layout, "dark", "compact");
}Next Steps
- Inline Styles: Style application
- Responsive Styles: Adaptive design
- StyleSheet Class: Global stylesheets
- Advanced Usage: Complex patterns