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:

css
: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:

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.button is unique per module
  • Combine module classes with optional className from parent

Conditional className

Template string:

tsx
<span className={isActive ? "nav-link active" : "nav-link"}>

clsx (optional):

bash
npm install clsx
tsx
import clsx from "clsx";
 
<article className={clsx("card", isFeatured && "card--featured", className)} />

Inline Styles

tsx
<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

text
components/
├── Card.tsx
├── Card.module.css
├── Button.tsx
└── Button.module.css

Feature folders:

text
features/posts/
├── PostList.tsx
├── PostList.module.css
└── hooks/

See Performance and Best Practices for folder layout.

CSS Architecture Tips

PracticeWhy
Semantic HTML firstStyle real <button>, not <div onClick>
Design tokens in :rootConsistent colors and spacing
Avoid !importantFix specificity instead
Focus stylesDo not remove outline without replacement — a11y CSS

Other Approaches (Awareness)

ApproachNotes
TailwindUtility classes—popular; learn via official docs
styled-componentsCSS-in-JS—runtime cost; team preference
Sass/LessPreprocessors—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.

Next chapter?

React Router Basics.