CSS Variables as Design Tokens: A Simple Approach to Design Systems
Design systems are essential in modern web development. They help maintain consistency, speed up development, and ensure a cohesive user experience across applications. For small teams or even solo developers, a design system can really make things easier. It cuts down on repeated design decisions by providing reusable components and design guidelines and allowing developers to focus on building features instead of worrying about inconsistencies. This leads to faster iterations, easier onboarding for new team members, and a more unified product.
CSS variables, or custom properties, are entities defined by CSS that let you store values for reuse throughout a document. They enable dynamic styling and can be updated at runtime, making them a powerful tool for creating flexible and maintainable design systems.
Why CSS Variables Are Good Enough
While there are many sophisticated design token solutions available, native CSS variables have evolved to be remarkably capable:
- They're built into the platform
- They cascade naturally through the DOM
- They can be updated dynamically
- They work with any framework (or no framework)
- They're performant
- Browser support is excellent
Introducing css-vars-design-token
The css-vars-design-token
package offers a lightweight approach to design tokens using CSS variables. It provides:
- Simple theme switching
- TypeScript support
- React integration
- Zero dependencies beyond React itself
Basic Usage
Here's a simple example:
// Create the `light` and `dark` themes.
const themes = {
light: {
color: {
primary: '#0066cc',
background: '#ffffff',
text: '#333333'
}
},
dark: {
color: {
primary: '#66b3ff',
background: '#1a1a1a',
text: '#ffffff'
}
}
};
// Wrap your components in a provider
function App() {
return (
<CssVarsDesignTokenProvider themes={themes}>
<MyComponents />
</CssVarsDesignTokenProvider>
);
}
Your CSS can then use these tokens:
.button {
background-color: var(--color-primary);
color: var(--color-text);
}
.card {
background-color: var(--color-background);
border: 1px solid var(--color-primary);
}
Advanced Features
Deep Tokens
The library automatically flattens deep token structures:
const themes = {
light: {
spacing: {
small: '0.5rem',
medium: '1rem',
large: {
default: '2rem',
mobile: '1.5rem'
}
}
}
};
This creates CSS variables like --spacing-small
, --spacing-medium
, --spacing-large-default
, and --spacing-large-mobile
.
Theme Switching
The library provides a hook for easy theme switching:
function ThemeToggle() {
const { theme, toggle } = useCssVarsDesignTokenContext();
return (
<button onClick={toggle}>
Current theme: {theme}
</button>
);
}
Real-World Applications
Responsive Design
CSS variables work seamlessly with media queries:
:root {
--sidebar-width: var(--layout-sidebar-default);
}
@media (max-width: 768px) {
:root {
--sidebar-width: var(--layout-sidebar-compact);
}
}
Component Libraries
Design tokens can help create consistent component libraries:
function Button({ variant = 'primary', children }) {
return (
<button
style={{
backgroundColor: `var(--color-${variant})`,
padding: 'var(--spacing-medium)',
borderRadius: 'var(--border-radius-medium)'
}}
>
{children}
</button>
);
}
You even have access to the current token values themselves, if needed:
function ({ children }) {
const { token } = useCssVarsDesignTokenContext()
const newColor = desaturate(token.color.backgroundColor)
return (
<div style={{ backgroundColor: newColor }}>
{children}
</div>
);
}
Benefits Over Alternative Approaches
- Simplicity: No build tools or preprocessors required
- Performance: CSS variables are highly optimized in modern browsers
- Developer Experience: Easy to debug using browser dev tools
- Framework Agnostic: The underlying CSS variables work everywhere
- Progressive Enhancement: Falls back gracefully if JavaScript fails
Getting Started
Install the package:
npm install css-vars-design-token
The library weighs less than 1KB gzipped and has zero dependencies beyond React.
Check out the GitHub repository for more examples and documentation.