← Back to Chapters

CSS Variables

? CSS Variables

⚡ Quick Overview

CSS Variables (also called custom properties) let you define reusable style values directly in CSS using the --name format. They work perfectly with React for building scalable, themeable UIs.

You can define them globally using :root, scope them to specific components, and even update them dynamically at runtime with JavaScript or React code.

In React projects, CSS variables are widely used for themes, colors, spacing, and light/dark modes.

? Key Concepts

  • Custom properties: CSS variables declared with a -- prefix.
  • Global scope: Usually defined in :root to be available everywhere.
  • Local overrides: Redefined on specific elements or components to customize behavior.
  • Usage with var(): Access variable values using var(--name).
  • Dynamic updates: Change variable values at runtime using the DOM API in React.
  • CSS Modules support: You can use and override CSS variables inside .module.css files.

? Syntax & Theory

Declaring CSS Variables:

  • Variables are declared inside any CSS selector using --variable-name: value;.
  • Global theme variables are typically placed inside :root so they cascade across the whole document.

Using CSS Variables:

  • Use the var() function to read values: color: var(--text-color);
  • You can provide fallbacks: color: var(--text-color, #333);

Local vs Global Behavior:

  • Variables follow normal CSS cascading rules.
  • A variable redefined on a nested element overrides the global value for that subtree only.

? Code Examples

1️⃣ Global CSS Variables & React Button

Define a theme in styles.css and use it in a React App component.

? View Code Example (styles.css)
// Define global theme variables
/* styles.css */
:root {
  --primary-color: #007bff;
  --secondary-color: #6c757d;
  --text-color: #333;
  --padding: 10px;
}

.button {
  background-color: var(--primary-color);
  color: white;
  padding: var(--padding);
  border: none;
  border-radius: 4px;
}
? View Code Example (App.js)
// Basic React component using the CSS variables
// App.js
import React from "react";
import "./styles.css";

function App() {
  return (
    <div className="text-center mt-4">
      <button className="button">Click Me</button>
    </div>
  );
}

export default App;

2️⃣ Local vs Global CSS Variables in a Card

Use a local variable --card-bg and override it when a .dark class is applied.

? View Code Example (Card.css)
// Card styles with local CSS variable overrides
/* Card.css */
.card {
  --card-bg: #ffffff;
  background-color: var(--card-bg);
  border-radius: 8px;
  padding: 20px;
}

.card.dark {
  --card-bg: #1c1c1c;
  color: white;
}
? View Code Example (Card.js)
// Toggle local CSS variable by switching class
// Card.js
import React, { useState } from "react";
import "./Card.css";

function Card() {
  const [dark, setDark] = useState(false);

  return (
    <div className={`card ${dark ? "dark" : ""}`}>
      <h4>Themed Card</h4>
      <p>This card uses local CSS variable overrides.</p>
      <button
        className="btn btn-outline-primary"
        onClick={() => setDark(!dark)}
      >
        Toggle Theme
      </button>
    </div>
  );
}

export default Card;

3️⃣ Updating CSS Variables via JavaScript in React

Update --primary-color at runtime using the DOM API to change the theme instantly.

? View Code Example (DynamicTheme.js)
// Dynamically change the CSS variable from React
// DynamicTheme.js
function DynamicTheme() {
  const setTheme = (color) => {
    document.documentElement.style.setProperty("--primary-color", color);
  };

  return (
    <div className="text-center mt-4">
      <button
        className="btn btn-primary me-2"
        onClick={() => setTheme("#007bff")}
      >
        Blue
      </button>
      <button
        className="btn btn-success me-2"
        onClick={() => setTheme("#28a745")}
      >
        Green
      </button>
      <button
        className="btn btn-danger"
        onClick={() => setTheme("#dc3545")}
      >
        Red
      </button>
      <div className="mt-3">
        <button className="button">Dynamic Themed Button</button>
      </div>
    </div>
  );
}

export default DynamicTheme;

4️⃣ CSS Variables in CSS Modules

Use CSS variables inside .module.css files and override them with different module classes.

? View Code Example (ThemeCard.module.css)
// Scoped variables inside a CSS Module
/* ThemeCard.module.css */
.card {
  --theme-bg: #f8f9fa;
  --theme-color: #333;
  background-color: var(--theme-bg);
  color: var(--theme-color);
  padding: 15px;
  border-radius: 8px;
}

.cardDark {
  --theme-bg: #333;
  --theme-color: #fff;
}
? View Code Example (ThemeCard.js)
// Combine module classes to override variables
// ThemeCard.js
import React, { useState } from "react";
import styles from "./ThemeCard.module.css";

function ThemeCard() {
  const [dark, setDark] = useState(false);

  return (
    <div className={`${styles.card} ${dark ? styles.cardDark : ""}`}>
      <h5>CSS Variables with Modules</h5>
      <p>Switch theme using CSS variable overrides.</p>
      <button
        className="btn btn-outline-secondary"
        onClick={() => setDark(!dark)}
      >
        Toggle Mode
      </button>
    </div>
  );
}

export default ThemeCard;

? Live Output & Explanation

In the examples above:

  • The global button gets its background from --primary-color. Changing the variable updates all buttons using it.
  • In the Card component, the default background comes from a local variable --card-bg. When the .dark class is applied, the value is overridden only for that card.
  • The DynamicTheme component directly updates --primary-color on document.documentElement, so any element using that variable updates immediately.
  • With CSS Modules, variables are still just CSS. They work normally and can be overridden by combining module classes like styles.card and styles.cardDark.

This pattern is perfect for building theme systems, especially when combined with React state and context.

? Tips & Best Practices

  • Define all major theme variables in a global :root so you can manage them from a single place.
  • Use meaningful names like --primary-bg, --text-color, and --border-radius instead of --blue or --nice-color.
  • Combine CSS variables with React Context or custom hooks to build a reusable theme manager.
  • Add transition properties (e.g., background-color 0.3s ease) to create smooth theme animations.
  • Prefer variables for any value that might change between themes (colors, fonts, spacing, shadows, etc.).

? Try It Yourself

  1. Define a global theme in :root with variables for primary/secondary colors, text color, and base spacing.
  2. Build a theme switcher (Light/Dark) in React that toggles a data-theme attribute and updates CSS variables using setProperty().
  3. Create a component using .module.css and use local CSS variables to override part of the global theme.
  4. Add smooth transitions between theme values (e.g., background-color, color) to make the switch feel polished.

Goal: Learn how to define, use, and update CSS variables in React so you can build scalable, easily themeable user interfaces.