08_React Component Styling - Maniconserve/React-Wiki GitHub Wiki

There are several ways to style React components. Each approach has its own use case.


1. Separate CSS File

The most familiar approach โ€” write styles in a .css file and import it into your component.

/* Card.css */

.card { background-color: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); }

.card-title { font-size: 24px; color: #333; }

// Card.jsx
import './Card.css';

function Card() {
  return (
    <div className="card">
      <h2 className="card-title">Hello</h2>
    </div>
  );
}

โœ… Clean separation of concerns โ€” styles stay out of JavaScript.
โŒ CSS is global by default โ€” a class named .card in one file affects every element with that class name across the entire app.


2. Inline Styles

Pass a JavaScript object directly to the style attribute. Property names are written in camelCase instead of kebab-case.

function Card() {
  return (
    <div style={{ backgroundColor: 'white', borderRadius: '8px', padding: '20px' }}>
      <h2 style={{ fontSize: '24px', color: '#333' }}>Hello</h2>
    </div>
  );
}

CSS property name changes

Because styles are JavaScript objects, hyphenated CSS properties become camelCase:

CSS JSX Inline Style
background-color backgroundColor
border-radius borderRadius
font-size fontSize
margin-top marginTop
padding-left paddingLeft
box-shadow boxShadow
z-index zIndex
text-align textAlign
flex-direction flexDirection

Part of the React Project Wiki โ€” see also: JSX Attributes & Expressions ยท React Components

# React Component Styling

There are several ways to style React components. Each approach has its own use case.


1. Separate CSS File

The most familiar approach โ€” write styles in a .css file and import it into your component.

/* Card.css */

.card {
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.card-title {
  font-size: 24px;
  color: #333;
}
// Card.jsx
import './Card.css';

function Card() {
  return (
    <div className="card">
      <h2 className="card-title">Hello</h2>
    </div>
  );
}

โœ… Clean separation of concerns โ€” styles stay out of JavaScript.
โŒ CSS is global by default โ€” a class named .card in one file affects every element with that class name across the entire app.


2. Inline Styles

Pass a JavaScript object directly to the style attribute. Property names are written in camelCase instead of kebab-case.

function Card() {
  return (
    <div style={{ backgroundColor: 'white', borderRadius: '8px', padding: '20px' }}>
      <h2 style={{ fontSize: '24px', color: '#333' }}>Hello</h2>
    </div>
  );
}

CSS property name changes

Because styles are JavaScript objects, hyphenated CSS properties become camelCase:

CSS JSX Inline Style
background-color backgroundColor
border-radius borderRadius
font-size fontSize
margin-top marginTop
padding-left paddingLeft
box-shadow boxShadow
z-index zIndex
text-align textAlign
flex-direction flexDirection

โœ… Scoped to that element โ€” no global conflicts.
โœ… Easy to make dynamic using variables.
โŒ No support for pseudo-classes like :hover, :focus, or media queries.
โŒ Gets messy for large amounts of styling.


3. CSS-in-JS (Style Object)

Define styles as a JavaScript object outside the JSX, then reference it. Keeps the JSX clean while still using inline style objects.

const styles = {
  card: {
    backgroundColor: 'white',
    borderRadius: '8px',
    padding: '20px',
    boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
  },
  title: {
    fontSize: '24px',
    color: '#333',
    marginTop: '0',
  },
  button: {
    backgroundColor: '#0070f3',
    color: 'white',
    padding: '10px 20px',
    borderRadius: '4px',
    border: 'none',
  },
};

function Card() {
  return (
    <div style={styles.card}>
      <h2 style={styles.title}>Hello</h2>
      <button style={styles.button}>Click Me</button>
    </div>
  );
}

โœ… All styles in one place, easy to read.
โœ… No class name conflicts.
โœ… Can reference JavaScript variables and constants.
โŒ Still no :hover, :focus, or media queries without a library.


4. CSS Modules

CSS Modules scope styles locally to the component by automatically generating unique class names. The file must be named Component.module.css.

/* Card.module.css */

.card {
  background-color: white;
  border-radius: 8px;
  padding: 20px;
}

.title {
  font-size: 24px;
  color: #333;
}
// Card.jsx
import styles from './Card.module.css';

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

React transforms .card into a unique class like Card_card__xK2p1 automatically, so it never clashes with any other .card class in the app.

โœ… Scoped โ€” no global conflicts even with the same class name.
โœ… Supports all CSS features โ€” :hover, media queries, animations.
โœ… Best of both worlds โ€” familiar CSS syntax with automatic scoping.
โŒ Slightly more setup than a plain CSS file.


5. Global CSS

Styles written in index.css or App.css (imported in index.js) apply to the entire application.

/* index.css */

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Arial', sans-serif;
  background-color: #f5f5f5;
  color: #222;
}

h1, h2, h3 {
  font-weight: 600;
}
// index.js
import './index.css'; // applied globally across the entire app

โœ… Ideal for resets, base typography, and app-wide defaults.
โŒ Affects every component โ€” can cause unintended style collisions.


6. Overriding Styles

Overriding with Inline Style

Inline styles always win over CSS class styles because they have the highest specificity in React.

/* App.css */
.title {
  color: black;
  font-size: 20px;
}
// Inline style overrides the CSS class
<h1 className="title" style={{ color: 'red' }}>Hello</h1>
// color will be red, font-size stays 20px from the class

Overriding with Multiple Class Names

Combine class names as a string to stack styles. The class that appears later in the CSS file wins when there is a conflict.

/* App.css */
.btn {
  background-color: grey;
  color: white;
  padding: 10px;
}

.btn-primary {
  background-color: blue; /* overrides .btn background */
}
<button className="btn btn-primary">Click</button>
// background will be blue (btn-primary wins), padding stays from .btn

Conditional Class Names

Apply classes conditionally based on state or props.

function Button({ isPrimary }) {
  return (
    <button className={`btn ${isPrimary ? 'btn-primary' : 'btn-secondary'}`}>
      Click Me
    </button>
  );
}

Comparison Summary

Method Scoped Hover / Media Queries Dynamic Values Best For
Separate CSS file โŒ Global โœ… โŒ Simple projects
Inline style โœ… โŒ โœ… Quick one-off styles
CSS-in-JS object โœ… โŒ โœ… Component-level style objects
CSS Modules โœ… โœ… โŒ Most React projects โœ…
Global CSS โŒ Global โœ… โŒ Resets and base styles

Recommended Approach

Scenario Use
App-wide resets and base fonts Global CSS (index.css)
Component-specific styles CSS Modules
Dynamic styles based on state or props Inline style or CSS-in-JS object
Quick prototype or small component Inline style

โš ๏ธ **GitHub.com Fallback** โš ๏ธ