Colors
Overview
The CivicTheme color system is a sophisticated, multi-layered approach to managing colours across components. It provides a flexible foundation for creating consistent, accessible, and themeable user interfaces that support both light and dark themes.
Quick Start
To use the CivicTheme color system:
- Define brand colours in - $ct-colors-brands(optional)
- Override default colours in - $ct-colors(optional)
- Use component variables in - _variables.components.scssfor specific styling
- Apply themes using the - ct-component-thememixin in component SCSS files
Color System Architecture
1. Base Color Foundation (_variables.base.scss)
_variables.base.scss)The color system is built on a foundation of semantic colour tokens that are mapped to actual colour values:
// Brand colours can be extended
$ct-colors-brands: () !default;
// Default colour palette can be overridden
$ct-colors: () !default;
// Default semantic colour mapping
$ct-colors-default: (
  'light': (
    'heading': ct-color-shade(ct-color-constant-light('brand1'), 60),
    'body': ct-color-tint(ct-color-shade(ct-color-constant-light('brand1'), 80), 20),
    'background-light': ct-color-tint(ct-color-constant-light('brand2'), 90),
    'background': ct-color-constant-light('brand2'),
    'interaction-background': ct-color-constant-light('brand1'),
    'interaction-text': ct-color-tint(ct-color-constant-light('brand2'), 80),
    // ... more semantic colours
  ),
  'dark': (
    'heading': ct-color-tint(ct-color-constant-dark('brand1'), 95),
    'body': ct-color-tint(ct-color-constant-dark('brand1'), 85),
    'background': ct-color-constant-dark('brand2'),
    'interaction-background': ct-color-constant-dark('brand1'),
    'interaction-text': ct-color-constant-dark('brand2'),
    // ... more semantic colours
  )
);2. Component-Specific Variables (_variables.components.scss)
_variables.components.scss)Component variables map semantic colours to specific component properties:
// Tag component variables
$ct-tag-light-primary-background-color: ct-color-light('interaction-background') !default;
$ct-tag-light-primary-color: ct-color-light('interaction-text') !default;
$ct-tag-dark-primary-background-color: ct-color-dark('interaction-background') !default;
$ct-tag-dark-primary-color: ct-color-dark('interaction-text') !default;How New Color Palettes Are Mapped
Step 1: Define Brand Colours (Optional)
To create a custom colour palette, start by defining your brand colours:
// In your theme's variables.base.scss
$ct-colors-brands: (
  'light': (
    'brand1': #0066cc,  // Primary brand colour
    'brand2': #f8f9fa,  // Secondary brand colour
    'brand3': #ff6b35,  // Accent brand colour
  ),
  'dark': (
    'brand1': #4d94ff,  // Primary brand colour (dark variant)
    'brand2': #1a1a1a,  // Secondary brand colour (dark variant)
    'brand3': #ff8c69,  // Accent brand colour (dark variant)
  )
);Step 2: Override Default Colours (Optional)
You can override specific semantic colours without changing the entire palette:
// In your theme's variables.base.scss
$ct-colors: (
  'light': (
    'interaction-background': #custom-primary,
    'interaction-text': #custom-text,
  ),
  'dark': (
    'interaction-background': #custom-primary-dark,
    'interaction-text': #custom-text-dark,
  )
);Step 3: Component Variables Automatically Update
Once you've defined your brand colours or overridden semantic colours, all component variables automatically use the new values because they reference the semantic colour functions:
// These automatically use your new colours
$ct-tag-light-primary-background-color: ct-color-light('interaction-background');
$ct-tag-light-primary-color: ct-color-light('interaction-text');How Light and Dark Theme Colours Are Applied
The ct-component-theme Mixin
ct-component-theme MixinThe ct-component-theme mixin is the core mechanism for applying theme-specific styles:
@mixin ct-component-theme($name) {
  @each $theme in light, dark {
    &.ct-theme-#{$theme} {
      @content($name, $theme);
    }
  }
}Component Implementation Pattern
Components use this pattern to apply theme-specific styles:
.ct-tag {
  $root: &;
  // Base styles (shared across themes)
  border-radius: $ct-tag-border-radius;
  display: inline-block;
  // Theme-specific styles
  @include ct-component-theme($root) using($root, $theme) {
    &#{$root}--primary {
      @include ct-component-property($root, $theme, primary, background-color);
      @include ct-component-property($root, $theme, primary, border-color);
      @include ct-component-property($root, $theme, primary, color);
    }
  }
}CSS Custom Properties Generation
The ct-component-property mixin generates CSS custom properties:
@mixin ct-component-property($args...) {
  $property: list.nth($args, list.length($args));
  #{$property}: ct-component-var($args...);
}This generates CSS like:
.ct-tag.ct-theme-light.ct-tag--primary {
  background-color: var(--ct-tag-light-primary-background-color);
  border-color: var(--ct-tag-light-primary-border-color);
  color: var(--ct-tag-light-primary-color);
}
.ct-tag.ct-theme-dark.ct-tag--primary {
  background-color: var(--ct-tag-dark-primary-background-color);
  border-color: var(--ct-tag-dark-primary-border-color);
  color: var(--ct-tag-dark-primary-color);
}Colour Function Resolution
The ct-color-light() and ct-color-dark() functions resolve to CSS custom properties:
@function ct-color-light($name) {
  @return _ct-color($name, 'light');
}
@function _ct-color($name, $theme, $is-flat: false) {
  // ... validation logic ...
  @if not $is-flat {
    $color: ct-component-var(ct, color, $theme, $name);
  }
  @return $color;
}This creates a chain: ct-color-light('interaction-background') → var(--ct-color-light-interaction-background) → actual colour value.
Variable Naming Convention
Component variables follow a strict naming pattern:
$ct-[component]-[theme]-[?subcomponent]-[?state]-[rule]Examples:
- $ct-tag-light-primary-background-color
- $ct-button-dark-secondary-hover-border-color
- $ct-navigation-light-dropdown-menu-item-active-background-color
Practical Example: Creating a Custom Tag Variant
To add a new "success" variant to the tag component:
- Add component variables in - _variables.components.scss:
$ct-tag-light-success-background-color: ct-color-light('success') !default;
$ct-tag-light-success-border-color: $ct-tag-light-success-background-color !default;
$ct-tag-light-success-color: white !default;
$ct-tag-dark-success-background-color: ct-color-dark('success') !default;
$ct-tag-dark-success-border-color: $ct-tag-dark-success-background-color !default;
$ct-tag-dark-success-color: white !default;- Add component styles in - tag.scss:
@include ct-component-theme($root) using($root, $theme) {
  // ... existing variants ...
  &#{$root}--success {
    @include ct-component-property($root, $theme, success, background-color);
    @include ct-component-property($root, $theme, success, border-color);
    @include ct-component-property($root, $theme, success, color);
  }
}Benefits of This System
- Semantic Colour Mapping: Colours are defined by purpose, not specific values 
- Automatic Theme Support: Light and dark themes are handled automatically 
- CSS Custom Properties: Enables runtime theme switching 
- Extensible: Easy to add new colours or override existing ones 
- Consistent: All components follow the same theming pattern 
- Maintainable: Changes to brand colours propagate throughout the system 
Key Files
- _variables.base.scss: Foundation colour definitions
- _variables.components.scss: Component-specific colour mappings
- mixins/_color.scss: Colour utility functions
- mixins/_component.scss: Theme application mixins
Next Steps
To implement a new colour palette:
- Define your brand colours in - $ct-colors-brands
- Override any semantic colours in - $ct-colorsif needed
- Test components in both light and dark themes 
- Use the existing component variables for consistency 
- Add new component variables following the naming convention 
Last updated
Was this helpful?
