Styling React Components
Introduction
React does not prescribe a styling system—you can use global CSS, CSS Modules, or CSS-in-JS libraries. This chapter covers practical patterns for Vite + React: global vs component styles, CSS Modules, conditional className, and accessibility-friendly styling—without adopting Tailwind or a full UI kit.
Prerequisites
Global vs Component CSS
src/index.css — resets, typography, CSS variables:
:root {
--color-text: #1a1a1a;
--color-bg: #ffffff;
--space-md: 1rem;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
color: var(--color-text);
background: var(--color-bg);
}src/App.css — imported in App.tsx:
import "./App.css";Global classes apply everywhere—watch naming collisions on large apps.
Compare Vue <style scoped> in Class, Style, and Transitions.
CSS Modules
Button.module.css:
Button.tsx:
Code explanation:
- Vite renames classes at build time—
styles.buttonis unique per module - Combine module classes with optional
classNamefrom parent
Conditional className
Template string:
<span className={isActive ? "nav-link active" : "nav-link"}>clsx (optional):
npm install clsximport clsx from "clsx";
<article className={clsx("card", isFeatured && "card--featured", className)} />Inline Styles
<div style={{ padding: "1rem", opacity: isDisabled ? 0.5 : 1 }}>Use for dynamic values (progress bar width). Prefer classes for static design tokens.
Co-located Files
components/
├── Card.tsx
├── Card.module.css
├── Button.tsx
└── Button.module.cssFeature folders:
features/posts/
├── PostList.tsx
├── PostList.module.css
└── hooks/See Performance and Best Practices for folder layout.
CSS Architecture Tips
| Practice | Why |
|---|---|
| Semantic HTML first | Style real <button>, not <div onClick> |
Design tokens in :root | Consistent colors and spacing |
Avoid !important | Fix specificity instead |
| Focus styles | Do not remove outline without replacement — a11y CSS |
Other Approaches (Awareness)
| Approach | Notes |
|---|---|
| Tailwind | Utility classes—popular; learn via official docs |
| styled-components | CSS-in-JS—runtime cost; team preference |
| Sass/Less | Preprocessors—optional with Vite |
This track stays on CSS Modules + global variables for clarity.
FAQ
CSS Modules in Vite?
Name files *.module.css—enabled by default.
Global class inside module?
Use :global(.theme-dark) .button sparingly—or keep theme vars in index.css.
Dark mode?
Toggle class on <html> or data-theme; switch CSS variables in Dark mode CSS.
Import order?
Global index.css in main.tsx first; component modules in each file.