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 variantaquabloom.tsβ "AquaBloom" theme variantshared-theme-config.tsβ Shared primitives, component configs, and color schemes
PrimeNG generates CSS custom properties from these presets automatically:
- Color scales:
--p-primary-50through--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β
- Tailwind classes first β Most common scenarios
- PrimeNG CSS variables β When Tailwind doesn't provide what you need
- 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β
| Category | Tailwind Classes | CSS Variables | Use Case |
|---|---|---|---|
| Primary | text-primary-default, bg-primary-hover | --p-primary-color | Primary actions, brand colors |
| Secondary | text-secondary-default, bg-secondary-hover | --p-secondary-color | Secondary actions |
| Text | text-text-primary, text-text-secondary | --p-text-primary | Text hierarchy |
| Background | bg-background-default, bg-background-surface | --p-background-default | Surfaces, cards |
| Border | border-border-default | --p-border-default | Borders, dividers |
| Semantic | text-positive-default, text-negative-default | --p-success-color, --p-danger-color | Success, 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.
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.tssrc/main/webapp/content/theming/custompreset.tssrc/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 themedarkβ Dark modeblossomβ Custom theme variantaquabloomβ Alternative theme variant
π Related Documentationβ
- 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/