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-componentsJSX
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.