Theming an app
@flyze/lib-core-angular 1.0.0-alpha.34· latestHow to register a theme, activate it, consume it in stylesheets, and control light/dark.
FlyzeThemingService is providedIn: 'root' and needs no setup: the built-in flyze theme is
applied on first injection, following the OS color scheme. Everything below is for customizing that.
Mechanics: features/theming. Every step on this page is running on the
/theming route of the playground app, including the mistakes it warns about.
Consume the theme in CSS
Section titled “Consume the theme in CSS”The service writes CSS custom properties onto :root, so components just use them:
.card { background: var(--system-secondary-system-background); color: var(--system-label); border: 1px solid var(--system-separator);}
.card__cta { background: var(--colors-flyze-default);}The variable name is the theme key with -- in front. Keys already carry their group prefix, so the
group (system / colors / platform) is not repeated in the variable name. The full list of
names is
flyze-default-theme.ts
— system-* for text/background/separator roles, colors-* for the palette, platform-* for shell
chrome and status colors.
Because it is CSS, a scheme or theme switch repaints without Angular re-rendering anything. Do not read colors into TypeScript to bind them into styles.
Register a custom theme
Section titled “Register a custom theme”constructor(private theming: FlyzeThemingService) {}
ngOnInit() { this.theming.setThemeConfig('acme', { light: { colors: { 'colors-flyze-default': '#0055ff' }, platform: { 'platform-shell-header': '#ffffff' } }, dark: { colors: { 'colors-flyze-default': '#4488ff' }, platform: { 'platform-shell-header': '#1c1c1e' } } });
this.theming.theme = 'acme';}Only override what differs — every key you leave out keeps its flyze default, in both halves.
Register before activating. Assigning an unknown name logs a warning and is ignored, so
theme = 'acme' before setThemeConfig('acme', …) silently leaves you on flyze. Do both in an
APP_INITIALIZER or the root component’s ngOnInit, and note that setThemeConfig replaces a
theme of the same name rather than extending it — call it once with the complete palette.
Values must be hex, rgb/rgba or hsl/hsla; the ThemeColor type rejects named colors.
Light and dark
Section titled “Light and dark”this.theming.customPreferredColorScheme = 'dark'; // force darkthis.theming.customPreferredColorScheme = 'auto'; // follow the OS (default)Read the current state from preferredColorScheme / preferredColorScheme$ — the effective value.
Bind a scheme toggle to customPreferredColorScheme and render the state from
preferredColorScheme$:
readonly scheme$ = this.theming.preferredColorScheme$;readonly isAuto$ = this.theming.customPreferredColorScheme$.pipe(map((s) => s === 'auto'));detectedPreferredColorScheme$ is the raw OS preference and only useful for showing what 'auto'
would resolve to. Persisting the user’s choice is the app’s job — the service does not.
One-off variables
Section titled “One-off variables”For values that are not part of a theme:
this.theming.setRootVariable('app-sidebar-width', '280px'); // --app-sidebar-widththis.theming.setMultipleRootVariables({ 'app-gap': '8px', 'app-radius': '12px' });this.theming.removeRootVariable('app-sidebar-width');These land in the same :root block, so a name colliding with a theme key will be overwritten on
the next theme or scheme change.
Shades of a color
Section titled “Shades of a color”const palette = this.theming.generateGradiationPalette('acme', 'light.colors.colors-flyze-default');// { 'colors-flyze-default': '#0055ff', 'colors-flyze-default-L10': 'color-mix(…);', … 'colors-flyze-default-D90': … }this.theming.setMultipleRootVariables(palette);L10–L90 mix toward white, D10–D90 toward black, in 10% steps.
Every generated entry ends with a stray ; (see the limitation in
features/theming). It survives being written into the :root block, but
strip it if you use a value anywhere else:
const shade = this.theming .getThemeValueGradiation('acme', 'light.colors.colors-flyze-default', { gradiationType: 'darker', gradiationPercentage: 20 }) .replace(/;$/, '');