Theming
RhombusKit themes through a three-tier token system — palette primitives → semantic CONTRACT names → light / dark theme packs. Flip the theme and the whole app re-themes from one contract; the swatches below are live.
Preference: system · Applied: rhombus-light
Token reference
The token names are the public, semver-covered contract; the values are a theme. Each swatch renders var(--name), so it tracks the active theme in real time.
--bg#f8fafc#020617--bg-subtle#f1f5f9#0f172a--surface-0#ffffff#0f172a--surface-1#f1f5f9#1e293b--surface-2#e2e8f0#334155--surface-3#cbd5e1#475569--text-primary#0f172a#f8fafc--text-secondary#475569#cbd5e1--text-muted#64748b#94a3b8--text-disabled#cbd5e1#475569--text-accent#7c3aed#a78bfa--text-on-accent#ffffff#ffffff--border#e2e8f0#334155--border-strong#94a3b8#64748b--border-accent#ddd6fergb(167 139 250 / 0.40)--focus-ringrgb(124 58 237 / 0.22)rgb(167 139 250 / 0.28)--focus-border#7c3aed#a78bfa--error#dc2626#ef4444--error-bg#fef2f2#2a0a0a--btn-primary-bg#7c3aed#7c3aed--btn-primary-text#ffffff#ffffff--btn-primary-hover#6d28d9#6d28d9--nav-active-bg#f5f3ffrgb(167 139 250 / 0.14)--nav-active-text#6d28d9#f8fafc--switch-track-off#cbd5e1#475569--switch-track-on#7c3aed#8b5cf6--tooltip-bg#0f172a#334155--tooltip-text#ffffff#ffffff--toast-info-bg#f1f5f9#1e293b--toast-info-text#334155#e2e8f0--toast-success-bg#f0fdf4#002a0f--toast-success-text#15803d#22c55e--toast-warning-bg#fffbeb#2a1f00--toast-warning-text#b45309#f59e0b--toast-error-bg#fef2f2#2a0a0a--toast-error-text#b91c1c#ef4444--status-draft-bg#fffbeb#2a1f00--status-draft-text#b45309#f59e0b--status-published-bg#f0fdf4#002a0f--status-published-text#15803d#22c55e--status-scheduled-bg#f5f3ff#1a0a3a--status-scheduled-text#7c3aed#a78bfa--status-archived-bg#f1f5f9#1e293b--status-archived-text#475569#94a3b8--ink-surface#0f172a#0f172a--ink-on-surface#f8fafc#f8fafc--code-keyword#6d28d9#c4b5fd--code-string#15803d#22c55e--code-function#b45309#f59e0b--code-number#b91c1c#ef4444--code-comment#64748b#94a3b8--code-punctuation#475569#cbd5e1Designing in Figma? The same contract is exported as design-tokens.json — W3C / Tokens Studio format, so Figma variables map 1:1 to these tokens.
Setup
Load the tokens first so later layers can reference the custom properties they declare, then register the theme runtime.
// styles.scss — order matters
@use '@rhombuskit/tokens/scss' as tokens;
@use '@rhombuskit/material-preset/scss' as preset;
@use '@rhombuskit/core/scss' as core;
// Opt in to the Material bridge on the element that carries data-theme,
// so every --mat-sys-* re-resolves per active theme + palette.
:root {
@include preset.material-bridge();
}// app.config.ts
import { provideRhombusTheme } from '@rhombuskit/theme-engine';
export const appConfig: ApplicationConfig = {
providers: [
provideRhombusTheme({ light: 'rhombus-light', dark: 'rhombus-dark' }),
],
}; To avoid a flash of the wrong theme, inject the pre-paint init script (THEME_INIT_SCRIPT / getThemeInitScript()) into <head>. It uses the same storage key and resolution as the service, so the first paint always matches.
Switch at runtime
Inject RhombusThemeService — signals for state, methods to change the preference. The choice persists under rhombuskit:theme-preference; 'system' follows the OS and re-resolves live.
import { RhombusThemeService } from '@rhombuskit/theme-engine';
private readonly theme = inject(RhombusThemeService);
this.theme.preference(); // 'rhombus-light' | 'rhombus-dark' | 'system'
this.theme.current(); // always concrete: 'rhombus-light' | 'rhombus-dark'
this.theme.setTheme('rhombus-dark');
this.theme.toggle(); // light -> dark -> system -> lightCustom themes
Add your own theme without touching the contract: augment ThemeRegistry so setTheme() type-checks, ship CSS for its [data-theme] selector, then register it.
// 1. Tell TypeScript the theme exists.
declare module '@rhombuskit/theme-engine' {
interface ThemeRegistry {
'midnight-light': true;
'midnight-dark': true;
}
}
// 2. Register it.
provideRhombusTheme({ light: 'midnight-light', dark: 'midnight-dark' });// 3. Ship the CONTRACT values for the theme.
[data-theme='midnight-dark'] {
--bg: #0b1020;
--surface-0: #131a2e;
--text-primary: #e6e9f2;
--btn-primary-bg: #6366f1;
// ...every CONTRACT name...
}The Material bridge
@rhombuskit/material-preset maps Angular Material's M3 system tokens (--mat-sys-*) onto the CONTRACT, so Material components inherit the active theme automatically — no .mat-mdc-* overrides and no hand-maintained mat.theme() mapping. It tracks Angular Material 21.x.
As of v1.9 the bridge is opt-in: include the material-bridge() mixin once at the element that carries data-theme (see Setup above). Because every value is a var(--contract-token), it tracks light/dark and every registered palette with no per-theme configuration — you can delete any local mat.theme() bridge SCSS.
The full guide lives in docs/theming.md.