DEV Community

ZNY
ZNY

Posted on

The Complete Guide to Building Design Systems with CSS Custom Properties in 2026

The Complete Guide to Building Design Systems with CSS Custom Properties in 2026

Design systems scale frontend development. CSS custom properties (variables) are the foundation — enabling theming, consistency, and maintainability.

Why CSS Custom Properties

Preprocessors like Sass have variables. But CSS custom properties are runtime:

/* Preprocessor: compiled away, no runtime access */
$primary: #0066cc;

/* CSS Custom Properties: live, dynamic */
:root {
  --primary: #0066cc;
  --primary-hover: #0052a3;
  --spacing-unit: 8px;
  --border-radius: 4px;
}

.button {
  background: var(--primary);
  padding: calc(var(--spacing-unit) * 1.5);
  border-radius: var(--border-radius);
}
Enter fullscreen mode Exit fullscreen mode

Runtime variables mean instant theming without JavaScript.

Design Token Architecture

Structure your variables hierarchically:

/* Layer 1: Primitives */
:root {
  --blue-50: #e6f0ff;
  --blue-100: #b3d1ff;
  --blue-500: #0066cc;
  --blue-900: #002d5c;

  --space-1: 4px;
  --space-2: 8px;
  --space-4: 16px;
  --space-8: 32px;
}

/* Layer 2: Semantic tokens */
:root {
  --color-primary: var(--blue-500);
  --color-primary-hover: var(--blue-900);
  --color-background: #ffffff;
  --color-text: #1a1a1a;

  --spacing-component: var(--space-4);
  --spacing-section: var(--space-8);
}

/* Layer 3: Component tokens */
.button-primary {
  --button-bg: var(--color-primary);
  --button-color: white;
  --button-padding: var(--spacing-component);
  background: var(--button-bg);
  color: var(--button-color);
  padding: var(--button-padding);
}
Enter fullscreen mode Exit fullscreen mode

Component Library Structure

/* components/button.css */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--button-gap, 8px);
  padding: var(--button-padding-y, 12px) var(--button-padding-x, 24px);
  border-radius: var(--button-radius, 6px);
  font-family: var(--font-family, inherit);
  font-size: var(--button-font-size, 1rem);
  font-weight: var(--button-font-weight, 600);
  transition: all 0.2s ease;
  cursor: pointer;
  border: none;
}

.button--primary {
  --button-bg: var(--color-primary);
  --button-color: white;
}

.button--secondary {
  --button-bg: transparent;
  --button-color: var(--color-primary);
  border: 2px solid var(--color-primary);
}

.button:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
Enter fullscreen mode Exit fullscreen mode

Dark Mode in One CSS File

:root {
  --color-bg: #ffffff;
  --color-text: #1a1a1a;
  --color-surface: #f5f5f5;
}

[data-theme="dark"] {
  --color-bg: #1a1a1a;
  --color-text: #f5f5f5;
  --color-surface: #2d2d2d;
}

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

.card {
  background: var(--color-surface);
  border-radius: 8px;
}
Enter fullscreen mode Exit fullscreen mode

Toggle with one attribute: document.documentElement.setAttribute('data-theme', 'dark').

Conclusion

CSS custom properties enable design systems that are maintainable, themeable, and component-scoped. Start with primitives, build semantic tokens, then component-level overrides. Your future self will thank you.

Design and ship faster with an all-in-one platform — includes templates and hosting so you can focus on your design system.

Top comments (0)