CSS Modules
In this page:
The Problem CSS Modules Solve
Regular CSS class names are global — a class called '.card' in one file can accidentally override or be overridden by a '.card' class defined elsewhere in a large app. CSS Modules solve this by automatically making class names locally scoped to whichever component imports that stylesheet.
Note: This problem grows worse as an app and team scale — CSS Modules are especially valuable in larger codebases with many contributors.
Warning: This is purely a build-time naming trick — it doesn't change how CSS itself works, just how class names are generated and matched up.
Example: The Problem CSS Modules Solve
// Run in your local React project (npm install required)
/* Card.module.css */
.card { border: 1px solid #ccc; padding: 16px; }
// Card.jsx
import styles from './Card.module.css';
function Card() {
return <div className={styles.card}>Content</div>;
}
How the Import Becomes an Object
Importing a .module.css file doesn't give you the raw CSS text — the build tool transforms it into a JavaScript object where each key is one of your original class names, and each value is a unique, generated class name (like card_a1b2c) that won't collide with anything else in the app.
Note: Console.log the imported styles object during development to see exactly what generated class names it contains.
Warning: Referencing styles.someClassName for a class that doesn't exist in the CSS file returns undefined, silently applying no class at all.
Example: How the Import Becomes an Object
// Run in your local React project (npm install required)
import styles from './Button.module.css';
function Button() {
console.log(styles); // { button: "button_a3f9c" }
return <button className={styles.button}>Click me</button>;
}
Combining Multiple Classes
When a component needs more than one CSS Modules class at once (like a base style plus a conditional variant), you combine the generated class name strings with template literals or a small helper, since JSX's className just wants one final string.
Note: Libraries like classnames or clsx make combining multiple conditional classes cleaner than manual string concatenation.
Warning: Concatenating class names with a plain '+' instead of a template literal or space-joining can accidentally merge two class names into one invalid string.
Example: Combining Multiple Classes
// Run in your local React project (npm install required)
import styles from './Button.module.css';
function Button({ primary }) {
const className = primary ? `${styles.button} ${styles.primary}` : styles.button;
return <button className={className}>Click me</button>;
}
- Forgetting the import syntax is different — you import the CSS file as an object (import styles from './App.module.css'), not as a side-effect import.
- Using regular string class names instead of the generated styles.className property.
- Naming the file just 'App.css' instead of 'App.module.css' — the '.module.css' suffix is what triggers CSS Modules processing in most build tools.
- CSS Modules scope class names locally to the component that imports them, avoiding global naming collisions.
- A file named Component.module.css is processed specially by the build tool (Vite, webpack, etc.).
- Imported styles become a JS object mapping your original class names to generated, unique ones.
- This is a build-tool feature, not a runtime library — no CDN equivalent exists for this preview sandbox.
Build-tool feature (Vite/webpack/Create React App all support it); no specific React version requirement.
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: