Skip to main content

Color Theming

TUMApply uses a comprehensive theming system built on PrimeNG Themes and Tailwind CSS v4. The system supports multiple themes with automatic dark mode detection and seamless switching.


πŸ—οΈ Architecture Overview​

Theme Sources (Single Source of Truth)​

src/main/webapp/content/theming/

  • tumapplypreset.ts β€” Main TUMApply theme (light + dark modes)
  • custompreset.ts β€” "Blossom" theme variant
  • aquabloom.ts β€” "AquaBloom" theme variant
  • shared-theme-config.ts β€” Shared primitives, component configs, and color schemes

PrimeNG generates CSS custom properties from these presets automatically:

  • Color scales: --p-primary-50 through --p-primary-950
  • Semantic tokens: --p-primary-color, --p-background-default, --p-text-primary, etc.
  • Component tokens: --p-button-background, --p-stepper-step-number-size, etc.

Tailwind Integration​

src/main/webapp/content/scss/_tokens.scss

Maps PrimeNG CSS variables to Tailwind-compatible color tokens. This enables Tailwind utility classes while maintaining a single source of truth in the PrimeNG presets.

@theme {
--color-primary-default: var(--p-primary-color);
--color-text-primary: var(--p-text-primary);
--color-background-default: var(--p-background-default);
// ... etc.
}

Global Styles​

src/main/webapp/content/scss/global.scss

@use 'tailwindcss' as *;
@use './tokens' as *;
@plugin "tailwindcss-primeui";
@custom-variant dark (&:where(.tum-apply-dark-mode, .tum-apply-dark-mode *));

Theme Service​

src/main/webapp/app/service/theme.service.ts

  • Manages theme switching (light, dark, blossom, aquabloom)
  • Syncs with system preferences via prefers-color-scheme
  • Persists user preference in localStorage
  • Applies theme by setting PrimeNG preset and CSS classes

βœ… Best Practices​

1. Always Use Semantic Colors​

βœ… Use Tailwind utility classes (PREFERRED):

<div class="text-primary-default bg-background-surface border-border-default">
<span class="text-text-secondary">Secondary text</span>
</div>

βœ… Use PrimeNG CSS variables (for custom SCSS):

.custom-element {
color: var(--p-text-primary);
background-color: var(--p-background-default);
border-color: var(--p-border-default);
}

❌ NEVER use hard-coded hex values:

<div style="color: #3070b3;">...</div>

2. Styling Priority​

  1. Tailwind classes first β€” Most common scenarios
  2. PrimeNG CSS variables β€” When Tailwind doesn't provide what you need
  3. Custom SCSS β€” Only when neither option works

3. Dark Mode Support​

Use Tailwind's dark: variant with the custom dark mode selector:

<div
class="bg-background-default text-text-primary
dark:bg-background-surface dark:text-text-secondary"
>
Adapts to theme automatically
</div>

The dark: variant works with the .tum-apply-dark-mode class applied to <html>.

4. Available Color Categories​

CategoryTailwind ClassesCSS VariablesUse Case
Primarytext-primary-default, bg-primary-hover--p-primary-colorPrimary actions, brand colors
Secondarytext-secondary-default, bg-secondary-hover--p-secondary-colorSecondary actions
Texttext-text-primary, text-text-secondary--p-text-primaryText hierarchy
Backgroundbg-background-default, bg-background-surface--p-background-defaultSurfaces, cards
Borderborder-border-default--p-border-defaultBorders, dividers
Semantictext-positive-default, text-negative-default--p-success-color, --p-danger-colorSuccess, error, warning states

5. Common Patterns​

Card/Panel:

<div class="bg-background-surface border border-border-default rounded-lg p-4">
<h3 class="text-text-primary font-semibold">Title</h3>
<p class="text-text-secondary text-sm">Description</p>
</div>

Status Indicators:

<span class="text-positive-default">Success</span>
<span class="text-negative-default">Error</span>
<span class="text-warning-default">Warning</span>

Interactive Elements:

<button
class="bg-primary-default text-text-on-primary
hover:bg-primary-hover active:bg-primary-active"
>
Click me
</button>

🎨 Theme Customization​

Shared vs Theme-Specific Config​

All three presets import shared configuration from shared-theme-config.ts:

  • shared-theme-config.ts β€” primitives (border radius), component overrides, and shared color schemes. Changes here apply to all themes automatically.
  • tumapplypreset.ts, custompreset.ts, aquabloom.ts β€” each defines its own color palette (primary, secondary, etc.). Changes to colors in one preset do not propagate to the others.
warning

If you add or change a color in one preset (e.g., a new primary shade in tumapplypreset.ts), you must add the equivalent in custompreset.ts and aquabloom.ts as well. Otherwise, those themes will fall back to PrimeNG defaults and look inconsistent.

Modifying Existing Themes​

Edit color definitions in:

  • src/main/webapp/content/theming/tumapplypreset.ts
  • src/main/webapp/content/theming/custompreset.ts
  • src/main/webapp/content/theming/aquabloom.ts

Example:

export const TUMApplyPreset = definePreset(Aura, {
semantic: {
primary: {
50: '#f3f6fc',
500: '#3070b3', // Main primary color
950: '#13243e',
},
// ... etc.
},
});

Component-Specific Overrides​

For PrimeNG component overrides using class vs prime-ng-overrides.scss, see the Client Styling page.

Adding New Tailwind Tokens​

Edit: src/main/webapp/content/scss/_tokens.scss

@theme {
--color-custom-highlight: var(--p-primary-100);
// Now use: class="bg-custom-highlight"
}

πŸ”„ Theme Switching​

Users can switch themes via the UI. The ThemeService handles:

  • Theme persistence in localStorage
  • System preference synchronization
  • CSS class application (.tum-apply-dark-mode, .tum-apply-blossom, .tum-apply-aquabloom)
  • PrimeNG preset updates

Available themes:

  • light β€” Default light theme
  • dark β€” Dark mode
  • blossom β€” Custom theme variant
  • aquabloom β€” Alternative theme variant

  • See Client Styling for styling best practices
  • See Client Development for Angular and TypeScript patterns
  • Component library structure in src/main/webapp/app/shared/components/