Styling and CSS-in-JS

React supports many styling approaches — from plain CSS to CSS-in-JS libraries. Each has trade-offs.

Plain CSS

CSS
/* src/components/Card.css */
.card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 16px;
    margin: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.card:hover {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}

.card-title {
    font-size: 1.2rem;
    font-weight: bold;
    margin-bottom: 8px;
}
JSX
import './Card.css';

function Card({ title, children }) {
    return (
        <div className="card">
            <h3 className="card-title">{title}</h3>
            <div>{children}</div>
        </div>
    );
}

Conditional Classes

JSX
function TodoItem({ todo }) {
    return (
        <li className={`todo-item ${todo.completed ? 'completed' : ''}`}>
            {todo.text}
        </li>
    );
}

// Or use classnames library
import cn from 'classnames';

<li className={cn('todo-item', { completed: todo.completed })}>

CSS Modules

Scoped class names — no conflicts:

CSS
/* Card.module.css */
.card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 16px;
}

.title {
    font-size: 1.2rem;
    font-weight: bold;
}
JSX
import styles from './Card.module.css';

function Card({ title, children }) {
    return (
        <div className={styles.card}>
            <h3 className={styles.title}>{title}</h3>
            <div>{children}</div>
        </div>
    );
}

Styled Components (CSS-in-JS)

Bash
npm install styled-components
JSX
import styled from 'styled-components';

const StyledCard = styled.div`
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 16px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    
    &:hover {
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
    }
`;

const Title = styled.h3`
    font-size: ${props => props.large ? '1.5rem' : '1.2rem'};
    font-weight: bold;
    color: ${props => props.theme.primary};
`;

function Card({ title, large, children }) {
    return (
        <StyledCard>
            <Title large={large}>{title}</Title>
            {children}
        </StyledCard>
    );
}

Inline Styles

JSX
function Badge({ color, children }) {
    return (
        <span style={{
            backgroundColor: color,
            color: 'white',
            padding: '4px 12px',
            borderRadius: '16px',
            fontSize: '0.85rem',
            fontWeight: 'bold',
        }}>
            {children}
        </span>
    );
}

Tailwind CSS (Utility-First)

JSX
function Card({ title, children }) {
    return (
        <div className="bg-white rounded-lg shadow-md p-4 hover:shadow-lg transition-shadow">
            <h3 className="text-lg font-bold mb-2">{title}</h3>
            <div className="text-gray-600">{children}</div>
        </div>
    );
}

function Button({ variant = 'primary', children }) {
    const variants = {
        primary: 'bg-blue-500 hover:bg-blue-600 text-white',
        secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-800',
        danger: 'bg-red-500 hover:bg-red-600 text-white',
    };

    return (
        <button className={`px-4 py-2 rounded font-medium transition-colors ${variants[variant]}`}>
            {children}
        </button>
    );
}

Comparison

Approach Pros Cons
CSS Files Simple, familiar Global scope, naming conflicts
CSS Modules Scoped, simple No dynamic styles
Styled Components Dynamic, scoped Bundle size, learning curve
Inline Styles Dynamic, simple No pseudo-selectors, verbose
Tailwind Fast development, consistent Verbose class strings

💡 Tip: For new projects, Tailwind CSS is the fastest way to build good-looking UIs. For component libraries, CSS Modules offer the best balance of simplicity and encapsulation.