Skip to main content

CSS Modules

1. Introduction to CSS Modules

What are CSS Modules?

CSS Modules is a CSS file in which all class names and animation names are scoped locally by default. It helps solve the problem of global CSS by automatically creating unique class names.

Key Benefits

  • Local Scoping
  • Avoiding Name Conflicts
  • Explicit Composition
  • Built-in with Create React App
  • Works with Webpack and other build tools

2. Basic Syntax

Creating a CSS Module

/* Button.module.css */
.button {
padding: 10px 15px;
border-radius: 4px;
}

.primary {
background-color: #3498db;
color: white;
}

.secondary {
background-color: #f1f1f1;
color: #333;
}

Importing and Using in React

import React from 'react';
import styles from './Button.module.css';

function Button({ variant = 'primary', children }) {
return (
<button
className={`${styles.button} ${styles[variant]}`}
>
{children}
</button>
);
}

3. Advanced Styling Techniques

Composition

/* Typography.module.css */
.base {
font-family: Arial, sans-serif;
line-height: 1.5;
}

.heading {
composes: base;
font-weight: bold;
font-size: 24px;
}

.subtitle {
composes: base;
color: #666;
font-size: 16px;
}

Combining Multiple Classes

import styles from './Typography.module.css';

function Title() {
return (
<h1 className={`${styles.heading} ${styles.base}`}>
Welcome
</h1>
);
}

4. Conditional Styling

Dynamic Class Application

import React from 'react';
import styles from './Button.module.css';

function Button({ isActive, children }) {
return (
<button
className={`
${styles.button}
${isActive ? styles.active : styles.inactive}
`}
>
{children}
</button>
);
}

5. Global Styles

Using Global Selectors

/* global.module.css */
:global(.app-container) {
max-width: 1200px;
margin: 0 auto;
}

.localClass {
color: blue;
}

6. Composition with External Classes

Importing Classes from Another Module

/* Button.module.css */
.button {
padding: 10px 15px;
}

/* Theme.module.css */
.primaryTheme {
background-color: #3498db;
color: white;
}

/* Form.module.css */
.submitButton {
composes: button from './Button.module.css';
composes: primaryTheme from './Theme.module.css';
}

7. TypeScript Integration

Type-Safe CSS Modules

import styles from './Button.module.css';

interface Props {
className?: string;
}

const Button: React.FC<Props> = ({ className, children }) => {
return (
<button
className={`${styles.button} ${className}`}
>
{children}
</button>
);
}

8. Performance Considerations

Best Practices

  • Keep CSS Modules small and focused
  • Avoid deep nesting
  • Use composition over complex inheritance
  • Minimize the use of dynamic class names

9. Common Patterns

Responsive Design

.container {
width: 100%;
}

@media (min-width: 768px) {
.container {
width: 750px;
}
}

Handling Pseudo-classes

.button {
background-color: #3498db;
}

.button:hover {
background-color: #2980b9;
}

.button:disabled {
opacity: 0.5;
cursor: not-allowed;
}

10. Webpack Configuration

Manual Setup

// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
}

11. Common Mistakes to Avoid

  • ❌ Don't use global styles extensively
  • ❌ Avoid complex, deeply nested selectors
  • ❌ Don't create too many small CSS modules
  • ❌ Prevent overusing dynamic class names

Conclusion

CSS Modules provide a powerful, scoped approach to styling in React applications, solving many common CSS challenges while maintaining readability and performance.

Quick Reference

  • ✅ Local Scoping
  • ✅ Explicit Composition
  • ✅ Type-Safe with TypeScript
  • ✅ Built-in with Create React App
  • ❗ Requires Build Tool Configuration

Pro Tip: Use CSS Modules for component-specific styles and consider CSS-in-JS for more dynamic styling needs.