CSS Custom Properties Reference

Everything about CSS variables β€” syntax, scoping, fallbacks, JavaScript interop, and patterns

What is CSS Variables Reference?

CSS Variables Reference (CSS Custom Properties) documents the syntax, inheritance behavior, and practical patterns for CSS custom properties (var()). Browse examples of design token systems, dark mode theming, component-level variables, and fallback values. Includes a live editor where you can define custom properties and see them applied across CSS rules in real time.

CSS custom properties (officially CSS Custom Properties for Cascading Variables, Level 1 -- W3C) allow you to define reusable values in CSS: --color-primary: #3b82f6; then reference with var(--color-primary). Unlike preprocessor variables (Sass $var, Less @var), CSS custom properties are live in the browser -- they can be changed with JavaScript, they cascade and inherit, and they respond to media queries and pseudo-classes. They are the foundation of runtime theming.

Key behaviors: custom properties cascade and inherit like any other CSS property. They can be redefined in narrower scopes (:root defines globals; .component redefines locally). They accept any valid value (colors, lengths, strings, even CSS functions). Fallback: var(--color, #default) provides a fallback if the variable is undefined. CSS Houdini's @property rule (Chrome 85+) allows registering variables with a type, initial value, and inheritance control -- enabling transitions on custom properties.

How to Use

  1. Browse the 'Patterns' section for common design token setups (colors, spacing, typography).
  2. Use the live editor: define --my-color: #3b82f6 in :root and see it update immediately.
  3. Check the 'Dark mode' section for a complete light/dark theme toggle implementation.
  4. See the 'JavaScript integration' examples for reading and writing CSS variables via JS.
  5. Reference the browser support table -- CSS custom properties work in all modern browsers.

Examples

Define and use a variable

Result: :root { --brand: #3b82f6; } .button { background: var(--brand); }

Dark mode theme

Result: :root { --bg: #fff; --text: #111; } @media (prefers-color-scheme: dark) { :root { --bg: #0d1117; --text: #e6edf3; } }

Fallback value

Result: color: var(--accent, #58a6ff); /* uses #58a6ff if --accent is not defined */

Frequently Asked Questions

What is the difference between CSS custom properties and Sass variables?

CSS custom properties (--var): live in the browser, cascade and inherit, can be changed with JavaScript at runtime, respond to media queries and pseudo-classes, available in any context including inline styles. Sass variables ($var): compile-time only -- they are replaced with their values during the build step and don't exist in the output CSS. Sass variables cannot respond to user interactions or media queries at runtime. Use case comparison: Sass variables for static values known at build time (grid breakpoints in calculations). CSS custom properties for theme values that change at runtime (dark mode, user preferences).

How do I change a CSS custom property with JavaScript?

Read: getComputedStyle(element).getPropertyValue('--my-color').trim(). Write (global): document.documentElement.style.setProperty('--my-color', '#ff0000'). Write (local): element.style.setProperty('--my-color', '#ff0000'). Remove (revert to inherited): element.style.removeProperty('--my-color'). Common pattern for theme switching: document.documentElement.setAttribute('data-theme', 'dark') -- then in CSS: [data-theme='dark'] { --bg: #0d1117; }. This approach is better than toggling a class because the attribute is more semantic and works with the :has() selector.

How do CSS custom properties cascade and inherit?

Custom properties cascade exactly like regular CSS properties -- a definition closer to the element wins over a more distant one. They inherit by default -- if a child element uses var(--color) and doesn't define it, it inherits from the nearest ancestor that does. Scope: define in :root for global values (accessible everywhere). Redefine in .component for component-level overrides. Example: :root { --size: 1rem; } .large { --size: 1.5rem; } p { font-size: var(--size); } -- paragraphs inside .large get 1.5rem, all others get 1rem. @property (Houdini) lets you opt out of inheritance.

What is @property and how does it enable CSS custom property transitions?

@property (CSS Houdini, Chrome 85+, Firefox 128+) registers a custom property with a type system: @property --hue { syntax: ''; inherits: false; initial-value: 0deg; }. Benefits: type safety (browser validates the value), transitions (registered properties can be transitioned/animated -- unregistered properties cannot because the browser doesn't know their type), non-inheritance (inherits: false makes it not cascade). Example: animate a hue rotation -- without @property, CSS cannot interpolate custom properties in transitions because they are opaque strings.

How should I structure CSS custom properties for a design system?

Recommended structure: two-layer token system. Primitive tokens (:root): --color-blue-500: #3b82f6; -- raw values, rarely used directly. Semantic tokens (:root): --color-primary: var(--color-blue-500); -- purpose-defined, used in components. Component tokens (.button): --button-bg: var(--color-primary); -- component-specific. Dark mode: redefine semantic tokens in @media (prefers-color-scheme: dark) or [data-theme=dark]. This structure means: changing --color-primary updates everything using it. Swapping the dark theme only requires redefining semantic tokens, not component tokens.

Related Tools