Design System Problems

CSS Custom Properties Tokens

January 15, 2026 • 5 min read

CSS Custom Properties Tokens

CSS custom properties provide the native web platform mechanism for implementing design tokens. Custom properties (often called CSS variables) enable runtime token values that cascade through the DOM, support theming, and integrate naturally with stylesheets. Understanding how CSS custom properties serve as the token consumption layer for web applications enables effective token system design.

What Are CSS Custom Properties Tokens

CSS custom properties are entities defined within CSS using the -- prefix notation. When used as the output format for design tokens, they provide a way for web applications to consume token values with native browser support.

Token transformation pipelines generate CSS custom property declarations from token source files:

:root {
  --color-primary: #3B82F6;
  --color-background: #ffffff;
  --spacing-md: 16px;
  --font-size-body: 1rem;
}

Applications then reference these properties using the var() function:

.button {
  background: var(--color-primary);
  padding: var(--spacing-md);
  font-size: var(--font-size-body);
}

This approach separates token definition from token usage, enabling centralized updates and runtime theming capabilities.

How CSS Custom Properties Tokens Work

CSS custom properties inherit through the DOM cascade, creating natural scoping behavior. Properties defined on :root are available globally. Properties defined on specific elements apply only within that subtree.

Global tokens typically target the :root pseudo-element:

:root {
  --color-text-primary: #171717;
  --color-text-secondary: #525252;
}

Theming leverages cascade by redefining properties under different selectors:

:root {
  --color-background: #ffffff;
  --color-text: #171717;
}

[data-theme="dark"] {
  --color-background: #171717;
  --color-text: #ffffff;
}

When the data-theme="dark" attribute is added to an element, all descendants receive the dark values. This enables theme switching without JavaScript style manipulation.

Scoped tokens can customize component appearance:

.card {
  --card-background: var(--color-background-surface);
  --card-padding: var(--spacing-lg);

  background: var(--card-background);
  padding: var(--card-padding);
}

.card--compact {
  --card-padding: var(--spacing-md);
}

The compact variant overrides only the padding token, demonstrating how local token scoping enables targeted customization.

Key Considerations

Common Questions

How should fallback values be handled?

The var() function accepts a fallback value that applies when the property is not defined:

.element {
  color: var(--color-text-primary, #171717);
}

Fallback strategies vary by design system philosophy.

No fallbacks treats undefined properties as errors that should be caught during development. If a property is not defined, the style fails, revealing the problem quickly.

Sensible fallbacks provide default values matching the expected token value. This guards against build failures or partial token loading while hiding potential issues.

Cascade fallbacks reference other custom properties:

color: var(--color-text-emphasis, var(--color-text-primary, black));

This creates a fallback chain that progressively degrades to simpler values.

Most design systems use minimal fallbacks in component code, relying on comprehensive token generation to ensure all referenced properties exist.

How should themes be implemented with custom properties?

Theme implementation approaches include attribute-based, class-based, and media query-based switching.

Attribute-based theming uses data attributes to scope theme overrides:

[data-theme="dark"] {
  --color-background: #1a1a1a;
}

JavaScript toggles the attribute: document.body.dataset.theme = 'dark'

Class-based theming uses CSS classes:

.theme-dark {
  --color-background: #1a1a1a;
}

Media query-based theming responds to system preferences:

@media (prefers-color-scheme: dark) {
  :root {
    --color-background: #1a1a1a;
  }
}

These approaches can combine. A common pattern uses media queries for initial theme selection while allowing user override via attributes or classes.

Server-side rendering considerations include generating appropriate theme attributes or classes during HTML generation to prevent flash of incorrect theme on load.

How do custom properties integrate with token pipelines?

Token pipelines transform source token definitions into CSS custom property declarations. Style Dictionary configuration for CSS output:

{
  platforms: {
    css: {
      transformGroup: 'css',
      buildPath: 'dist/css/',
      files: [{
        destination: 'tokens.css',
        format: 'css/variables',
        options: {
          selector: ':root'
        }
      }]
    }
  }
}

The transformation handles name conversion (token paths to CSS property names), value formatting (ensuring valid CSS values), and file generation (producing properly formatted CSS).

For theming, separate outputs can be generated:

files: [
  {
    destination: 'light.css',
    format: 'css/variables',
    filter: (token) => token.filePath.includes('light'),
    options: { selector: ':root' }
  },
  {
    destination: 'dark.css',
    format: 'css/variables',
    filter: (token) => token.filePath.includes('dark'),
    options: { selector: '[data-theme="dark"]' }
  }
]

This produces separate CSS files or combined files with different selectors for each theme.

Summary

CSS custom properties serve as the primary mechanism for consuming design tokens in web applications. Their cascade behavior enables scoped customization and theming without JavaScript manipulation. Token pipelines generate custom property declarations from source definitions, providing the bridge between abstract tokens and concrete CSS values. Understanding custom property capabilities and patterns enables effective token implementation for web platforms.

Buoy scans your codebase for design system inconsistencies before they ship

Detect Design Drift Free
← Back to Token Management