CSS Modules

Scope CSS to a single component with a .module.css file to avoid class-name collisions.

Syntaximport styles from './x.module.css'; className={styles.card}

CSS Modules let you write regular CSS that is automatically scoped to one component. Name the file Something.module.css, import it as an object, and use the generated class names. Next.js supports them out of the box.

Why scoped CSS?

Class names are made unique at build time, so a .title in one module never clashes with a .title in another.

Example

Example · typescript
/* app/card.module.css */
.card { padding: 1rem; border: 1px solid #eee; }

// app/card.tsx
import styles from './card.module.css';

export default function Card() {
  return <div className={styles.card}>Hello</div>;
}

When to use it

  • A button component uses a CSS Module so its styles never conflict with another button styled in a different module.
  • A card component defines unique class names in card.module.css that are locally scoped and tree-shaken if unused.
  • A large codebase avoids global CSS specificity wars by requiring each component to own a .module.css file.

More examples

Define and apply a module

Importing the module file gives a styles object whose keys map to locally scoped class names.

Example · ts
// components/Button.module.css
.btn { background: blue; color: white; padding: 0.5rem 1rem; }

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

export default function Button({ label }: { label: string }) {
  return <button className={styles.btn}>{label}</button>;
}

Compose multiple classes

Template literals combine multiple scoped class names conditionally without a helper library.

Example · ts
// Card.module.css
.card { border: 1px solid #ddd; padding: 1rem; }
.active { border-color: blue; }

// Card.tsx
import styles from './Card.module.css';

export default function Card({ active }: { active: boolean }) {
  return (
    <div className={`${styles.card} ${active ? styles.active : ''}`}>
      Content
    </div>
  );
}

CSS Module with keyframe

@keyframes defined inside a CSS Module are also locally scoped and won't clash with global animations.

Example · ts
/* Spinner.module.css */
@keyframes spin { to { transform: rotate(360deg); } }
.spinner { width: 24px; height: 24px; border: 3px solid #eee; border-top-color: blue; border-radius: 50%; animation: spin 0.8s linear infinite; }

Discussion

  • Be the first to comment on this lesson.