CSS Modules scope plain CSS to a single component, while Tailwind CSS styles components through small utility classes written directly in the JSX. One keeps styles in separate files, the other moves them into the markup. The right choice depends on how much raw CSS you want to write and how fast you need a consistent design.
The difference at a glance
| CSS Modules | Tailwind CSS | |
|---|---|---|
| Styles live in | .module.css files | Class names in JSX |
| Scoping | Automatic per file | Reusable utilities |
| Learning curve | Plain CSS | New class vocabulary |
| Output | Only imported CSS | Only used utilities |
| Extra tooling | None in Vite | Vite or PostCSS plugin |
The table is the whole decision in miniature. CSS Modules add scoping to CSS you already know, while Tailwind asks you to learn utility names and gives speed in return.
CSS Modules: scoped CSS files
A CSS Module is a normal CSS file with a .module.css suffix. Vite turns every class in it into a unique name, so the same class name can safely appear in several files.
/* Card.module.css */
.card {
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}The component imports the file and reads a class name from the returned object. Vite scopes every class automatically because the file name ends in .module.css.
import styles from "./Card.module.css";
function Card() {
return <div className={styles.card}>A card with scoped styles.</div>;
}The browser applies the same padding, radius, and shadow as any plain CSS card. The difference is invisible to users but important to maintainers: the class name is unique to this component, so it cannot leak into another one.
Tailwind: utility classes in JSX
Tailwind skips separate CSS files for component styles and uses utility classes that each set one property. The same card is written entirely in the JSX.
function Card() {
return (
<div className="rounded-lg p-4 shadow-md">
A card styled with utility classes.
</div>
);
}Each class maps to a small CSS rule that Tailwind generates at build time. rounded-lg sets the radius, p-4 sets the padding, and shadow-md sets the shadow, and the final stylesheet contains only the utilities your code actually uses.
How each approach handles change
Both approaches handle responsive and state styles, just through different syntax. CSS Modules write media queries and pseudo-classes in the CSS file, while Tailwind adds prefixed variants such as hover: and md: to a class.
For example, a card that grows on wider screens uses a media query in CSS Modules and a md: prefix in Tailwind. The mechanics of breakpoints are the same, so the same mobile-first rules apply to both syntaxes.
Which should you use
- Choose CSS Modules when you want to keep writing CSS and only need scoping.
- Choose Tailwind when you want speed, consistency, and fewer naming decisions.
- Choose CSS Modules when designers hand you CSS to translate directly.
- Choose Tailwind when the team moves fast and reuses a shared set of utilities.
There is no performance winner in practice. Both compile to static CSS, so decide on workflow and how much of the styling language you want to own.
One common confusion
People often treat the two as rivals and forget they can coexist. A project can use CSS Modules for complex page components and Tailwind utilities for spacing and layout in the same app.
The broader view of where each fits among every styling option is in how to style React components, and the full setup steps are in the Tailwind walkthrough.
Rune AI
Key Insights
- CSS Modules scope plain CSS to one component per file.
- Tailwind styles components with small utility classes in JSX.
- CSS Modules ship only the CSS you import, Tailwind only the utilities you use.
- Both work in Vite with little or no configuration.
- They can be combined in one project.
Frequently Asked Questions
Do CSS Modules need a plugin in Vite?
Does Tailwind replace all my CSS?
Which is better for a beginner?
Conclusion
CSS Modules and Tailwind CSS solve the same problem from opposite directions. CSS Modules scope plain CSS per file, while Tailwind moves small utility classes into the markup, and the better fit depends on how much raw CSS you want to write.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.