Using CSS Custom Properties to Modify Components

Build dynamic, themable, and maintainable component systems with native CSS variables

What Are CSS Custom Properties

CSS custom properties, commonly known as CSS variables, are native CSS features that enable developers to create dynamic, maintainable, and themable component systems. Unlike preprocessor variables that are static and replaced at compile time, CSS custom properties live in the browser and can be changed dynamically based on user interaction, device preferences, or application state.

Key characteristics of CSS custom properties:

  • Defined using two dashes as a prefix: --property-name
  • Accessed using the var() function: color: var(--property-name)
  • Live in the browser's CSSOM and can be modified at runtime
  • Follow CSS cascade and inheritance rules
  • Can be manipulated through JavaScript

These capabilities make custom properties essential for modern web development, enabling component architectures that adapt to different contexts without requiring separate stylesheets or framework-specific solutions. For related techniques, explore our guide on the power of CSS :has() selector for advanced component targeting.

Declaring and Using Custom Properties
1:root {2  --primary-color: #3498db;3  --spacing-unit: 1rem;4  --font-size-base: 1rem;5}6 7.button {8  background-color: var(--primary-color);9  padding: var(--spacing-unit) calc(var(--spacing-unit) * 2);10  font-size: var(--font-size-base);11}
Why Use Custom Properties for Components

Key benefits for modern component development

Runtime Flexibility

Modify component appearance dynamically based on user interaction, device preferences, or application state without page reloads.

Theming Support

Implement dark mode, high contrast, or brand themes by redefining variable values in scoped selectors.

Maintainable Architecture

Centralize design decisions in tokens, enabling consistent updates across entire component libraries.

JavaScript Integration

Read and write custom property values from JavaScript for interactive customization and dynamic effects.

Button Component with Custom Properties
1.button {2  /* Base customizable properties */3  --button-background: var(--color-primary);4  --button-text: #ffffff;5  --button-border: none;6  --button-border-radius: 0.5rem;7  --button-padding: 0.75rem 1.5rem;8  --button-font-size: 1rem;9  --button-transition: all 0.2s ease;10 11  background: var(--button-background);12  color: var(--button-text);13  border: var(--button-border);14  border-radius: var(--button-border-radius);15  padding: var(--button-padding);16  font-size: var(--button-font-size);17  transition: var(--button-transition);18}19 20/* Variant overrides */21.button--outline {22  --button-background: transparent;23  --button-border: 2px solid var(--color-primary);24  --button-text: var(--color-primary);25}
Token Hierarchy Implementation
1:root {2  /* Primitive tokens - raw design values */3  --color-blue-500: #3498db;4  --color-blue-600: #2980b9;5  --color-gray-100: #f5f5f5;6  --color-gray-900: #1a1a1a;7  --spacing-1: 0.25rem;8  --spacing-2: 0.5rem;9  --spacing-4: 1rem;10 11  /* Semantic tokens - contextual usage */12  --color-primary: var(--color-blue-500);13  --color-primary-hover: var(--color-blue-600);14  --color-surface: var(--color-gray-100);15  --color-text: var(--color-gray-900);16  --spacing-section: var(--spacing-4);17}18 19/* Theme overrides */20[data-theme="dark"] {21  --color-surface: var(--color-gray-900);22  --color-text: var(--color-gray-100);23}
Reading and Setting Custom Properties
1// Reading a custom property value2const element = document.querySelector('.my-component');3const currentColor = getComputedStyle(element)4  .getPropertyValue('--component-color');5 6// Setting a custom property value7element.style.setProperty('--component-color', '#ff6b6b');8 9// Setting with CSS custom property reference10element.style.setProperty(11  '--component-background',12  'var(--theme-accent)'13);14 15// Theme switching example16function setTheme(themeName) {17  document.documentElement.setAttribute('data-theme', themeName);18}
Animated Custom Properties
1.card {2  --card-elevation: 0;3  --card-scale: 1;4  5  transform: scale(var(--card-scale));6  box-shadow: 0 calc(var(--card-elevation) * 4px) 7    calc(var(--card-elevation) * 12px) rgba(0, 0, 0, 0.15);8  transition: all 0.3s ease;9}10 11.card:hover {12  --card-elevation: 2;13  --card-scale: 1.02;14}15 16/* JavaScript can also update these values */17/* document.querySelector('.card').style.setProperty('--card-elevation', '3'); */

Frequently Asked Questions

How are CSS custom properties different from Sass variables?

Sass variables are compile-time only and don't exist in the final CSS, while CSS custom properties live in the browser and can be modified at runtime, enabling dynamic theming and JavaScript manipulation.

Can custom properties improve performance?

Yes, when used appropriately. Custom properties can reduce repeated values, enable efficient theme switching without repaints, and work with browser optimization for transform and opacity animations.

How do I implement dark mode with custom properties?

Define theme-specific values within scoped selectors (like [data-theme="dark"]). Adding the attribute to the document element causes all components using those variables to automatically update.

Should I use design tokens or raw values for custom properties?

Use design tokens as the foundation. Raw values should be tokenized for consistency, with semantic tokens referencing primitives to enable flexible theming and easy updates.

Build Dynamic Component Systems with Modern CSS

Our team specializes in creating scalable, maintainable component architectures using CSS custom properties, design tokens, and modern frontend technologies.