Theming

Build light and dark themes with Sass and CSS custom properties.

Syntax:root { --color: #{$value}; } color: var(--color);

The strongest theming approach combines both worlds: use Sass to organize and generate tokens at build time, and emit CSS custom properties so themes can switch live in the browser.

The pattern

  1. Define theme maps in Sass (light, dark).
  2. Loop with @each to emit custom properties under a theme selector.
  3. Reference the custom properties with var() in your components.

This gives you Sass's authoring power and CSS's runtime flexibility together.

Example

Example · css
$themes: (
  'light': (bg: #ffffff, text: #333333),
  'dark':  (bg: #1a1a1a, text: #eeeeee),
);

@use 'sass:map';
@each $name, $tokens in $themes {
  .theme-#{$name} {
    --bg:   #{map.get($tokens, bg)};
    --text: #{map.get($tokens, text)};
  }
}

body {
  background: var(--bg);
  color: var(--text);
}

When to use it

  • A SaaS product uses Sass maps to define light and dark themes, then emits CSS custom properties from each map under a data-theme attribute selector.
  • A developer builds a white-label system where each client's theme is a small Sass map that overrides brand colors, all compiled into separate CSS files.
  • A team co-locates their Sass theme maps with a @forward so any module can read theme values, while the :root generation happens only once in main.scss.

More examples

Light and dark theme maps

Two maps define light and dark tokens; a mixin emits them as CSS custom properties scoped to :root and [data-theme=dark] respectively.

Example · css
$light: (bg: #ffffff, text: #111827, border: #e5e7eb);
$dark:  (bg: #0f172a, text: #f1f5f9, border: #1e293b);

@mixin apply-theme($map) {
  @each $k, $v in $map {
    --#{$k}: #{$v};
  }
}

:root             { @include apply-theme($light); }
[data-theme=dark] { @include apply-theme($dark);  }

Component using theme tokens

A component references CSS custom properties set by the theme system, automatically switching between light and dark with zero extra CSS.

Example · css
.card {
  background: var(--bg);
  color:      var(--text);
  border:     1px solid var(--border);
  padding:    1rem;
  transition: background 0.2s, color 0.2s;
}

Multi-brand theme compilation

Each brand file configures the shared theme-system module with its own tokens, producing an independent CSS file per brand.

Example · css
// brand-a.scss
@use 'theme-system' with (
  $primary: #dc2626,
  $font:    'Georgia, serif'
);

// brand-b.scss
@use 'theme-system' with (
  $primary: #7c3aed,
  $font:    'Inter, sans-serif'
);
// Each compiles to a separate CSS file for white-labelling.

Discussion

  • Be the first to comment on this lesson.