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#cbd5e1

Designing 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.

scss
// 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();
}
typescript
// 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.

typescript
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 -> light

Custom 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.

typescript
// 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' });
scss
// 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.