Concept lesson · explains an idea. Code is shown for reading, not run.
There is no single best way to style React apps. Each approach moves some costs around. This lesson compares them fairly so you can choose, and explains what to look for when a team has already chosen.
The options
| Approach | What it is | Strengths | Costs |
|---|---|---|---|
| Plain CSS files | .css files imported into components | Nothing new to learn; full CSS; fast; works everywhere | Global scope: you manage names and specificity yourself |
| CSS Modules | .module.css: real CSS with locally scoped class names | Scoped without extra syntax; zero runtime cost; works with all CSS features | Generated class names; an import per file; dynamic values need inline styles or variables |
| Sass / SCSS | A CSS preprocessor (variables, nesting, mixins) compiled at build time | Familiar to many teams; helpful for large style sheets | Another build step; native CSS now has variables and nesting, so the gap is smaller than before |
| Utility classes (for example Tailwind CSS) | Small single-purpose classes in the markup (p-4 text-sm) | Fast to write and consistent; unused CSS is removed; no naming | Long className strings; a vocabulary to learn; design rules live in config |
| CSS-in-JS | Styles written in JavaScript and attached to components (styled-components, Emotion and others) | Styles that follow props naturally; co-located | Libraries that compute styles at run time add JavaScript work and need extra setup for server rendering. Some do not support the newest React features, so check a library’s status before adopting it |
| Compile-time CSS-in-JS | Styles written in JavaScript but extracted into CSS at build time | Co-location without most runtime cost | Needs bundler integration; a smaller ecosystem |
| Inline styles | The style prop | Perfect for computed values | No hover, media queries or pseudo-elements; hard to override |
Questions that decide it
- What does the team already know? A familiar tool beats a “better” unfamiliar one.
- Is performance critical? Build-time approaches (plain CSS, Modules, Tailwind, compile-time CSS-in-JS) send plain CSS to the browser. Run-time CSS-in-JS costs extra work in the browser.
- Will you use server rendering or React Server Components? Plain CSS, CSS Modules, utility classes and compile-time CSS-in-JS fit most easily. Run-time CSS-in-JS may need special support.
- Do you need a design system with tokens? CSS variables work with every approach and are worth using regardless.
- How big is the project? A small app is fine with plain CSS. A large team benefits from scoping (Modules) or conventions (utilities) that prevent clashes.
- Does the existing codebase already use one? Consistency matters more than purity.
A sensible default
If you are starting and have no strong reasons, begin with plain CSS or CSS Modules plus CSS variables. They are standard web technology, have no runtime cost, are easy to read, and skills transfer to any project. Add Tailwind or Sass when you have a team reason for them.
Things that help with every approach
- Design tokens as CSS variables: colours, spacing, radii and font sizes in one place.
- A small, consistent set of component styles instead of one-off values.
- Accessible defaults: visible focus, sufficient contrast, readable font sizes and respect for
prefers-reduced-motion. See Accessible Focus States. - Mobile-first, flexible layouts rather than fixed pixel widths. See Responsive Components.
- Component libraries (such as Radix, React Aria, MUI, or others) when you need accessible complex widgets like menus and dialogs. Compare their licences, styling model and maintenance before you commit.
Mixing is normal
Many projects combine them: global CSS for tokens and resets, CSS Modules for components, and inline styles or CSS variables for computed values. Just make sure everyone knows which is used for what.
Do not let the styling choice distract you
Whichever method you pick, your component logic stays the same: props and state decide which class names or values apply. That is the part this course teaches. You can change the styling tool later, as long as your components keep their styles at the component level (Component-Level Styling).
Key points
- Every approach trades simplicity, scoping, runtime cost and tooling differently.
- Plain CSS or CSS Modules plus CSS variables is a safe, standards-based default.
- Choose by team skills, performance and rendering needs, and check a library’s maintenance before adopting it.