SyRF Theming Guide¶
Comprehensive reference for the SyRF frontend theme system, design tokens, and styling standards.
Overview¶
SyRF uses Angular Material 21 with a custom Material Design 2 (M2) theme. The theme system consists of:
| Layer | Purpose | Files |
|---|---|---|
| Color Palette | Raw color definitions in Material hue format | syrf-palette.scss |
| Design Tokens | Semantic variables for spacing, typography, elevation, z-index | _design-tokens.scss |
| Theme Config | Material theme objects (light + dark) | syrf-theme.scss |
| Component Themes | Per-component color/typography mixins | *-theme.scss files |
| Global Styles | Overrides, utilities, legacy Bootstrap | styles.scss |
File Structure¶
src/global-styles/
_design-tokens.scss # Centralized design tokens (NEW)
syrf-palette.scss # SyRF primary + secondary Material palettes
syrf-theme.scss # Theme creation, component theme aggregation
styles.scss # Global overrides, utilities, MDC patches
legacy-bootstrap/ # Bootstrap 3 CSS subset (deprecated, pending removal)
buttons.scss
panel.scss
progress-bars.scss
src/app/
**/[component]-theme.scss # Component theme mixins (11 files)
Color System¶
Brand Palette¶
The SyRF brand uses a dark navy primary and cool gray secondary:
| Role | Hue | Value | Usage |
|---|---|---|---|
| Primary 500 | Default | #203457 |
Headers, nav, primary buttons |
| Primary 300 | Lighter | #637189 |
Hover states, accents |
| Primary 700 | Darker | #182746 |
Active states |
| Primary A100 | Accent light | #698dff |
Links |
| Secondary 500 | Default | #c6cad2 |
Borders, dividers |
| Secondary A200 | Accent | #2e4a7d |
Secondary actions |
| Warn 500 | Default | #f44336 |
Material red |
Semantic Colors¶
Defined in _design-tokens.scss for consistent use across the app:
| Token | Value | Usage |
|---|---|---|
$color-success |
#4caf50 |
Success states, confirmations |
$color-warning |
#ff9800 |
Warnings, staging indicators |
$color-error |
#f44336 |
Errors, validation failures |
$color-info |
#2196f3 |
Informational messages |
$color-text-primary |
rgba(0,0,0,0.87) |
Primary text |
$color-text-secondary |
rgba(0,0,0,0.6) |
Secondary/help text |
$color-text-disabled |
rgba(0,0,0,0.38) |
Disabled text |
Light and Dark Themes¶
Both themes are defined in syrf-theme.scss:
// Light (default)
$syrf-theme: mat.m2-define-light-theme((
color: (primary: $syrf-app-primary, accent: $syrf-app-accent, warn: $syrf-app-warn)
));
// Dark (activated by .global-dark-theme class on root element)
$syrf-dark-theme: mat.m2-define-dark-theme((
color: (primary: $syrf-app-primary, accent: $syrf-app-accent, warn: $syrf-app-warn)
));
Dark theme is applied via CSS class toggle:
Component Theme Pattern¶
All component themes follow the standard Angular Material mixin pattern:
@use 'sass:map';
@use '@angular/material' as mat;
@mixin color($config-or-theme) {
$config: mat.m2-get-color-config($config-or-theme);
$primary: map.get($config, primary);
$accent: map.get($config, accent);
$warn: map.get($config, warn);
$background: map.get($config, background);
$foreground: map.get($config, foreground);
.my-element {
color: mat.m2-get-color-from-palette($primary);
background-color: mat.m2-get-color-from-palette($background, card);
}
}
@mixin typography($config-or-theme) {
// Typography overrides (optional)
}
@mixin density($config-or-theme) {
// Density overrides (optional)
}
@mixin theme($theme-or-color-config) {
$color: if(
map.has-key($theme-or-color-config, color),
mat.m2-get-color-config($theme-or-color-config),
$theme-or-color-config
);
@if $color != null { @include color($color); }
}
Registration: Each component theme is imported and included in syrf-theme.scss:
@use '../app/my-component/my-component-theme' as my-component;
@include mat.all-component-themes($syrf-theme);
@include my-component.theme($syrf-theme);
.global-dark-theme {
@include mat.all-component-themes($syrf-dark-theme);
@include my-component.theme($syrf-dark-theme);
}
Existing Component Themes¶
| Component | File | Status |
|---|---|---|
| Sidenav | core/syrf-material/sidenav/_sidenav-theme.scss |
Good - proper theme usage |
| Banner | info/banner/banner.component.theme.scss |
Good - includes typography mixin |
| Home | info/home/home.component.theme.scss |
Good |
| Information Box | shared/information-box/_information-box.component-theme.scss |
Good - handles dark theme |
| Membership Table | project/project-admin/project-members/membership-table/_membership-table-theme.scss |
Stub - no active styles |
| Chips Email Input | shared/chips-emails-input/_chips-email-input-theme.scss |
Needs fix - uses !important |
| Project Nav | project/project-nav/_project-nav.component-theme.scss |
Needs fix - hardcoded colors |
| Incomplete Studies | stage/stage-review/incomplete-studies/_incomplete-studies.component-theme.scss |
Good |
| Edit (Questions) | project/project-admin/question-management/edit/_edit.component-theme.scss |
Good |
| Chip Label | shared/chip-label/_chip-label.component-theme.scss |
Good |
Design Tokens¶
Import from _design-tokens.scss:
Spacing (4px grid)¶
| Token | Value | Usage |
|---|---|---|
$spacing-1 |
4px | Tight spacing (icons, inline elements) |
$spacing-2 |
8px | Default component internal padding |
$spacing-3 |
12px | Moderate padding |
$spacing-4 |
16px | Standard padding (cards, sections) |
$spacing-6 |
24px | Section margins |
$spacing-8 |
32px | Large section gaps |
$spacing-12 |
48px | Page-level sections |
Z-Index Scale¶
| Token | Value | Usage |
|---|---|---|
$z-index-base |
0 | Default |
$z-index-dropdown |
100 | Dropdown menus |
$z-index-sticky |
200 | Sticky headers |
$z-index-nav |
300 | Navigation bar |
$z-index-overlay |
400 | Overlays |
$z-index-modal-backdrop |
500 | Modal backdrops |
$z-index-modal |
600 | Modals/dialogs |
$z-index-tooltip |
800 | Tooltips |
$z-index-cover |
1000 | Full-page loading overlay |
$z-index-impersonation |
1040 | Admin impersonation banner |
Border Radius¶
| Token | Value | Usage |
|---|---|---|
$radius-xs |
2px | Subtle rounding |
$radius-sm |
4px | Buttons, inputs (Material default) |
$radius-md |
8px | Cards, dialogs |
$radius-lg |
16px | Chips, pills |
$radius-full |
50% | Avatars, circular badges |
Typography Scale¶
Based on Material Design 2 type scale with Roboto:
| Token | Size | Usage |
|---|---|---|
$font-size-headline-5 |
24px | Page titles |
$font-size-headline-6 |
20px | Section headers |
$font-size-subtitle-1 |
16px | Subtitles, form labels |
$font-size-body-1 |
16px | Primary body text |
$font-size-body-2 |
14px | Secondary body text |
$font-size-caption |
12px | Captions, help text |
Styling Rules¶
Do¶
- Use theme mixins for colors that need to adapt to light/dark mode
- Use design tokens for static semantic values (spacing, z-index, radii)
- Use
mat.m2-get-color-from-palette()inside theme mixins - Use CSS custom properties for values that change at runtime
- Use
mat.elevation()for shadows on Material components - Keep component styles scoped via Angular's ViewEncapsulation
Don't¶
- Never hardcode hex colors in component SCSS - use palette functions or design tokens
- Never use inline styles in HTML templates - move to component SCSS
- Never use
!important- fix specificity with better selectors - Never add arbitrary z-index values - use the z-index scale tokens
- Never use Bootstrap classes for new development - use Angular Material
- Never target internal Material class names (e.g.,
.mat-form-field-wrapper) - these change between versions
Legacy Bootstrap¶
Three Bootstrap 3 CSS files are included for backward compatibility:
| File | Classes Used | Replacement |
|---|---|---|
buttons.scss |
.btn-*, .btn-group |
mat-button, mat-raised-button |
panel.scss |
.panel-* |
mat-card, mat-expansion-panel |
progress-bars.scss |
.progress-bar-* |
mat-progress-bar |
These are deprecated and should not be used in new components. They remain only for existing components that have not yet been migrated.
Known Issues (Technical Debt)¶
Hardcoded Colors (~80 instances)¶
Components with hardcoded colors that should use theme palette or design tokens:
app.component.scss- banner colors, link hover colorsproject-nav.component-theme.scss-#ffffff,#dddddd,#f2f2f2,#ff6565about.component.scss- multiple rgba and brand colorserror-recovery-dialog.component.scss- 9+ distinct hardcoded colorsstudy-table.component.scss- table row colorsdesign.component.scss- tree branch line colors
MDC Migration TODOs (~20 instances)¶
Selectors targeting pre-MDC internal classes like .mat-form-field-wrapper, .mat-form-field-infix. These need updating to target current MDC class names or use official component APIs.
!important Declarations (~42 instances)¶
Concentrated in question-management components. These indicate CSS specificity issues that should be resolved with proper selector structure.
Inline Styles (~61 instances)¶
HTML style="..." attributes that should be moved to component SCSS. Worst offenders are in review data upload, question management, and project overview components.
Related Documentation¶
- Material 3 Migration Plan - Upgrade path to M3
- Angular Material Theming Guide
- Material Design 2 Color System