React offers multiple ways to style your components. Each approach has its own benefits and use cases.
Styling Approaches
CSS Modules
Regular CSS
Inline Styles
CSS Modules provide scoped CSS that won’t conflict with other components.Import CSS Module
import cesese from './ItemCounter.module.css';
CSS Module File
.item-row {
display: flex;
align-items: center;
gap: 10px;
margin-top: 10px;
}
.item-text {
width: 200px;
}
.color-red {
color: yellow;
}
Using CSS Module Classes
<section className={cesese['item-row']}>
<span className="item-text">{name}</span>
</section>
CSS Modules automatically scope class names to prevent conflicts. Use bracket notation cesese['item-row'] for class names with hyphens.
Traditional CSS files work with className references.Import CSS
import './ItemCounter.css';
CSS File
.item-row {
display: flex;
align-items: center;
gap: 10px;
margin-top: 10px;
}
.item-text {
width: 200px;
}
Using CSS Classes
<section className="item-row">
<span className="item-text">{name}</span>
</section>
Regular CSS classes are global and can affect other components. Use unique class names or prefer CSS Modules.
Apply styles directly using JavaScript objects.Dynamic Inline Styles
<span
className="item-text"
style={{
color: count === 0 ? 'red' : 'black',
}}
>
{name}
</span>
Static Inline Styles
<section
style={{
display: 'flex',
alignItems: 'center',
gap: 10,
margin: 10
}}
>
{/* Content */}
</section>
Inline styles are great for dynamic values based on state or props. Use CSS/CSS Modules for static styles.
Complete Styling Example
Here’s a component using all three styling approaches:
import { useState } from "react";
import cesese from './ItemCounter.module.css';
interface Props {
name: string;
quantity?: number;
}
export const ItemCounter = ({ name, quantity }: Props) => {
const [count, setCount] = useState(Number);
const handleAdd = () => {
setCount(count + 1);
};
const handleSub = () => {
if (count === 0) return;
setCount(count - 1);
};
return (
<section
className={cesese['item-row']}
// Commented out: alternative inline style approach
// style={{
// display: 'flex',
// alignItems: 'center',
// gap: 10,
// margin: 10
// }}
>
<span
className="item-text"
style={{
color: count === 0 ? 'red' : 'black',
}}
>
{name}
</span>
<button onClick={handleAdd}>+1</button>
<span>{count}</span>
<button onClick={handleSub}>-1</button>
</section>
);
};
CSS Properties in JSX
Use camelCase
CSS property names become camelCase in JSX:// CSS: background-color
// JSX: backgroundColor
style={{
backgroundColor: 'red',
borderRadius: 10
}}
Values are strings or numbers
Most values are strings. Numbers without units are treated as pixels.style={{
color: 'red', // string
padding: 10, // number → 10px
width: '100%', // string with unit
gap: 10 // number → 10px
}}
Use double braces
Inline styles use double braces: outer for JSX, inner for the object.
Conditional Styling
Apply different styles based on state or props:
Conditional Colors
style={{
color: count === 0 ? 'red' : 'black',
}}
Conditional Classes
className={isActive ? 'active-class' : 'inactive-class'}
Multiple Conditional Classes
className={`base-class ${isActive ? 'active' : ''} ${isLarge ? 'large' : ''}`}
CSS Modules vs Regular CSS
| Feature | CSS Modules | Regular CSS |
|---|
| Scope | Local to component | Global |
| Import | import styles from './file.module.css' | import './file.css' |
| Usage | className={styles.className} | className="className" |
| Conflicts | No conflicts | Can conflict |
| File name | *.module.css | *.css |
CSS Modules require the .module.css file extension to work properly.
Best Practices
Use CSS Modules for component styles
CSS Modules prevent naming conflicts and keep styles scoped to components.import styles from './Component.module.css';
Use inline styles for dynamic values
Inline styles are perfect for values that change based on state.style={{ color: count === 0 ? 'red' : 'black' }}
Extract complex inline styles
For complex inline styles, create a variable:const containerStyle = {
display: 'flex',
alignItems: 'center',
gap: 10
};
<section style={containerStyle}>
Organize CSS files
Keep CSS files next to their components:ItemCounter.tsx
ItemCounter.module.css
Common Flexbox Patterns
Horizontal Layout
.item-row {
display: flex;
align-items: center;
gap: 10px;
margin-top: 10px;
}
Fixed Width Text
.item-text {
width: 200px;
}
Use flexbox (display: flex) with gap for spacing instead of margins between items. It’s cleaner and more maintainable.