We use cookies to enhance your experience on the site
CodeWorlds

CSS Modules - Isolated Control Panels

CSS Modules are one of the most popular ways to style in React. They work like a system of isolated control panels on a spaceship -- each module has its own controls that don't interfere with others.

What are CSS Modules?

CSS Modules are regular CSS files with the

.module.css
extension. The difference is that all class names are automatically unique -- React generates unique identifiers, so styles from one component never override styles of another.

1/* SpacePanel.module.css */
2.panel {
3  background: #0d1137;
4  border: 2px solid #3949ab;
5  border-radius: 12px;
6  padding: 20px;
7}
8
9.title {
10  color: #7c4dff;
11  font-size: 24px;
12  margin-bottom: 16px;
13}
14
15.statusActive {
16  color: #00e676;
17  font-weight: bold;
18}

Importing and using

We import a CSS Module as an object and reference classes like object properties:

1import styles from './SpacePanel.module.css';
2
3function SpacePanel({ title, status }) {
4  return (
5    <div className={styles.panel}>
6      <h2 className={styles.title}>{title}</h2>
7      <span className={styles.statusActive}>
8        Status: {status}
9      </span>
10    </div>
11  );
12}

In the generated HTML, the

panel
class becomes something like
SpacePanel_panel_x7k2f
-- completely unique!

Combining classes

We often need to combine multiple CSS classes. In CSS Modules, we can do this in several ways:

1// Template literal
2<div className={`${styles.panel} ${styles.dark}`}>
3
4// With condition
5<div className={`${styles.panel} ${isActive ? styles.active : ''}`}>
6
7// Array with join
8<div className={[styles.panel, styles.dark].join(' ')}>

Compose -- style inheritance

CSS Modules offer a special

composes
directive that allows inheriting styles from other classes:

1/* base.module.css */
2.baseButton {
3  padding: 10px 20px;
4  border: none;
5  border-radius: 6px;
6  cursor: pointer;
7  font-size: 14px;
8  transition: all 0.3s ease;
9}
10
11/* SpaceButton.module.css */
12.primaryButton {
13  composes: baseButton from './base.module.css';
14  background: #7c4dff;
15  color: white;
16}
17
18.dangerButton {
19  composes: baseButton from './base.module.css';
20  background: #f44336;
21  color: white;
22}

Thanks to

composes
, we avoid duplicating styles while maintaining isolation.

Global styles in CSS Modules

If you need a global class (e.g., for external libraries), use

:global
:

1/* Layout.module.css */
2:global(.container) {
3  max-width: 1200px;
4  margin: 0 auto;
5}
6
7.localClass {
8  /* This is local */
9  color: #64b5f6;
10}

Dynamic classes with CSS Modules

We often need to change styles based on props or state. Here are some patterns:

1import styles from './Alert.module.css';
2
3function Alert({ type = 'info', message }) {
4  // Dynamically selecting a class based on the prop
5  const alertClass = styles[type]; // styles.info, styles.warning, styles.error
6
7  return (
8    <div className={`${styles.alert} ${alertClass}`}>
9      <p className={styles.message}>{message}</p>
10    </div>
11  );
12}
1/* Alert.module.css */
2.alert {
3  padding: 16px;
4  border-radius: 8px;
5  border-left: 4px solid;
6}
7
8.info {
9  background: #1a237e;
10  border-color: #64b5f6;
11  color: #90caf9;
12}
13
14.warning {
15  background: #4a3800;
16  border-color: #ffa726;
17  color: #ffcc80;
18}
19
20.error {
21  background: #4a0000;
22  border-color: #f44336;
23  color: #ef9a9a;
24}

Notice that

styles[type]
lets you dynamically select a class based on a variable -- it's like switching modes on a control panel.

The classnames / clsx library

For more complex class combinations, it's worth using the

clsx
or
classnames
library:

1import clsx from 'clsx';
2import styles from './Button.module.css';
3
4function SpaceButton({ variant, size, disabled }) {
5  return (
6    <button className={clsx(
7      styles.button,
8      styles[variant],     // styles.primary or styles.secondary
9      styles[size],         // styles.small or styles.large
10      { [styles.disabled]: disabled }  // conditionally
11    )}>
12      Engage!
13    </button>
14  );
15}

Advantages of CSS Modules

  • Style isolation -- no class name conflicts, each component has its own "capsule"
  • Plain CSS -- no need to learn new syntax, you use the same CSS as always
  • Native support in Create React App and Next.js -- zero configuration
  • Lightweight -- no additional libraries in the bundle, zero runtime JS
  • Easy migration from existing CSS -- just change the file extension and import
  • Typing -- you can generate TypeScript types for CSS classes (e.g., via
    typed-css-modules
    )

CSS Modules are a solid, proven choice for styling React components. They're like reliable control panels on a spaceship -- simple, predictable, and conflict-free.

Go to CodeWorlds