cssVars
Creates CSS custom properties (variables) from JavaScript objects with automatic reactivity support.
API
function cssVars(vars: Record<string, any>, options?: CSSVarsOptions): any
vars
: Object containing CSS variable definitions. Can include nested objects and reactive signals.options
: Optional configuration for scoping and prefixing- Returns: Proxy object with
var()
references to the CSS custom properties
Options
interface CSSVarsOptions {
scoped?: string; // CSS selector to scope variables to
prefix?: string; // Prefix for all CSS variable names
}
scoped
: CSS selector to limit variable scope (e.g.,.theme-container
,#app
,[data-theme]
)prefix
: Prefix added to all CSS variable names for namespace organization
Basic Usage
import { cssVars } from '@hellajs/css';
const theme = cssVars({
colors: {
primary: '#3b82f6',
secondary: '#64748b'
},
spacing: {
small: '0.5rem',
medium: '1rem',
large: '2rem'
}
});
// theme.colors.primary = 'var(--colors-primary)'
// theme.colors.secondary = 'var(--colors-secondary)'
// theme.spacing.small = 'var(--spacing-small)'
Key Concepts
Using Variables in CSS
import { css, cssVars } from '@hellajs/css';
const theme = cssVars({
colors: {
primary: '#3b82f6',
background: '#ffffff'
}
});
const buttonStyle = css({
backgroundColor: theme.colors.primary,
color: theme.colors.background,
padding: '0.75rem 1.5rem',
border: 'none',
borderRadius: '0.5rem'
});
Reactive CSS Variables (NEW)
CSS variables automatically update when signals change:
import { signal } from '@hellajs/core';
import { cssVars, css } from '@hellajs/css';
const ThemeExample = () => {
const isDark = signal(false);
const primaryColor = signal('#3b82f6');
// Reactive CSS variables - automatically update when signals change
const theme = cssVars({
colors: {
primary: primaryColor, // Direct signal
background: () => isDark() ? '#1a1a1a' : '#ffffff', // Computed value
text: () => isDark() ? '#ffffff' : '#000000'
}
});
const buttonStyle = css({
backgroundColor: theme.colors.primary,
color: theme.colors.text,
padding: '0.75rem 1.5rem',
border: 'none',
borderRadius: '0.5rem'
});
return (
<div>
<button
class={buttonStyle}
onClick={() => isDark(!isDark())}
>
Toggle Theme
</button>
<button onClick={() => primaryColor('#059669')}>
Change Color
</button>
</div>
);
};
Complex Reactive Theming
import { signal, computed, batch } from '@hellajs/core';
import { cssVars, css } from '@hellajs/css';
const AdvancedTheme = () => {
const baseHue = signal(220); // Blue
const saturation = signal(70);
const lightness = signal(50);
// Complex computed CSS variables
const theme = cssVars({
colors: {
primary: () => `hsl(${baseHue()}, ${saturation()}%, ${lightness()}%)`,
secondary: () => `hsl(${baseHue() + 30}, ${saturation()}%, ${lightness() + 20}%)`,
background: () => `hsl(${baseHue()}, ${saturation() / 4}%, 95%)`,
},
spacing: {
base: () => lightness() > 60 ? '1rem' : '0.75rem' // Responsive spacing
}
});
const cardStyle = css({
backgroundColor: theme.colors.background,
color: theme.colors.primary,
padding: theme.spacing.base,
borderLeft: `4px solid ${theme.colors.secondary}`,
borderRadius: '0.5rem'
});
const randomizeTheme = () => {
batch(() => {
baseHue(Math.floor(Math.random() * 360));
saturation(50 + Math.floor(Math.random() * 40));
lightness(40 + Math.floor(Math.random() * 40));
});
};
return (
<div class={cardStyle}>
<h3>Dynamic Theme</h3>
<p>Theme updates automatically when signals change</p>
<button onClick={randomizeTheme}>Randomize Theme</button>
</div>
);
};
Mixed Static and Reactive Variables
const mixedTheme = cssVars({
// Static values (no reactivity)
fonts: {
body: 'system-ui, sans-serif',
mono: 'Menlo, monospace'
},
// Reactive values (with signals)
colors: {
primary: primaryColorSignal, // Direct signal
accent: () => getAccentColor(), // Computed function
surface: '#ffffff' // Static value
}
});
Performance Features
CSS variables automatically optimize performance through:
- Static Detection: Non-reactive objects use fast static path
- Reactive Tracking: Only creates effects when functions are detected
- Smart Caching: Identical static objects are cached and reused
- Memory Management: Effects are automatically cleaned up
Scoping and Prefixing
Control where CSS variables are applied and how they’re named:
import { signal } from '@hellajs/core';
import { cssVars, css } from '@hellajs/css';
const ThemeScoping = () => {
const primaryColor = signal('#3b82f6');
// Scoped to specific selector
const themeVars = cssVars({
primary: primaryColor,
secondary: '#64748b',
spacing: {
small: '0.5rem',
medium: '1rem'
}
}, {
scoped: '.theme-container',
prefix: 'my-theme'
});
// Global variables with prefix only
const globalVars = cssVars({
fontFamily: 'system-ui, sans-serif',
borderRadius: '0.25rem'
}, {
prefix: 'app'
});
const buttonStyle = css({
background: themeVars.primary, // var(--my-theme-primary)
padding: themeVars.spacing.medium, // var(--my-theme-spacing-medium)
fontFamily: globalVars.fontFamily, // var(--app-fontFamily)
borderRadius: globalVars.borderRadius, // var(--app-borderRadius)
border: 'none',
color: 'white',
cursor: 'pointer'
});
return (
<div class="theme-container">
<button
class={buttonStyle}
onClick={() => primaryColor('#dc2626')}
>
Scoped Button
</button>
{/* Variables only work within .theme-container */}
<p style={{ color: themeVars.secondary }}>
This uses scoped variables
</p>
</div>
);
};
Generated CSS:
- Scoped:
--my-theme-primary
,--my-theme-spacing-medium
(only in.theme-container
) - Global:
--app-fontFamily
,--app-borderRadius
(available everywhere)
Integration with Core Primitives
Works seamlessly with all reactive primitives:
import { signal, computed, effect } from '@hellajs/core';
const colorSignal = signal('#ff0000');
const computed_color = computed(() => adjustBrightness(colorSignal(), 0.8));
const theme = cssVars({
colors: {
primary: colorSignal, // Direct signal
primaryLight: computed_color, // Computed signal
custom: () => mixColors() // Custom function
}
});
Important Considerations
Type Safety
Maintains full TypeScript support with nested object typing:
interface ThemeVars {
colors: {
primary: string;
secondary: string;
};
spacing: {
base: string;
};
}
const theme: ThemeVars = cssVars({
colors: {
primary: '#3b82f6', // ✓ Valid
secondary: primarySignal // ✓ Valid (signal)
},
spacing: {
base: '1rem' // ✓ Valid
}
});
Memory Management
Use cssVarsReset to clean up all CSS variables and reactive effects when needed:
import { cssVarsReset } from '@hellajs/css';
// Clean up all CSS variables and reactive effects
cssVarsReset();