Chapter 18: Styling in React
In React, there are many ways to style components. Each method has its strengths, trade-offs, and best use cases. Today we’ll cover the four most popular and modern approaches in 2026:
- Inline styles (quick & simple)
- CSS Modules (scoped, reliable)
- Styled-components / Emotion (CSS-in-JS, dynamic styles)
- Tailwind CSS (utility-first, fastest for modern apps)
We’ll go very slowly and clearly, like I’m sitting next to you in Mumbai explaining everything live with complete, copy-paste-ready examples.
1. Inline Styles (Quick & Simple – But Limited)
Inline styles = writing CSS directly in the style prop as a JavaScript object.
Pros:
- Super fast to write
- Dynamic styles (easy to use state/props)
- No extra files
Cons:
- No pseudo-classes (:hover, :focus)
- No media queries
- No nesting
- Hard to maintain in big components
- No reusability
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
function InlineButton() { const [isHovered, setIsHovered] = useState(false); return ( <button onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} style={{ padding: '12px 24px', fontSize: '18px', backgroundColor: isHovered ? '#535bf2' : '#646cff', color: 'white', border: 'none', borderRadius: '8px', cursor: 'pointer', transition: 'background-color 0.3s ease', boxShadow: isHovered ? '0 4px 12px rgba(100, 108, 255, 0.4)' : 'none' }} > Hover Me! </button> ); } |
Best use: Small one-off styles, dynamic values (colors from theme, sizes from props).
2. CSS Modules (Scoped CSS – Very Clean & Reliable)
CSS Modules = normal CSS files where class names are automatically scoped to the component (no global pollution).
Pros:
- Scoped styles (no accidental overrides)
- Full CSS power (pseudo-classes, media queries, nesting with PostCSS)
- Works with any CSS preprocessor (Sass, Less…)
- Easy to read & maintain
Cons:
- Need to import CSS file
- Class names become long (hashed)
Setup (Vite already supports it out of the box)
Create file: src/components/Button.module.css
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* Button.module.css */ .primary { padding: 12px 24px; font-size: 18px; background-color: #646cff; color: white; border: none; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; } .primary:hover { background-color: #535bf2; transform: translateY(-2px); box-shadow: 0 4px 12px rgba(100, 108, 255, 0.4); } .secondary { background-color: transparent; border: 2px solid #646cff; color: #646cff; } .secondary:hover { background-color: #646cff; color: white; } |
Use in component:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import styles from './Button.module.css'; function StyledButton() { return ( <div style={{ padding: '40px', display: 'flex', gap: '20px' }}> <button className={styles.primary}> Primary Button </button> <button className={styles.secondary}> Secondary Button </button> {/* You can combine classes */} <button className={`${styles.primary} ${styles.secondary}`}> Combined </button> </div> ); } |
Pro tip: Use camelCase for class names → styles.primaryButton
3. Styled-components / Emotion (CSS-in-JS – Dynamic & Powerful)
CSS-in-JS = write CSS inside JavaScript components.
Popular libraries:
- styled-components (most popular)
- Emotion (lighter, faster)
Pros:
- Full dynamic styles (props, theme, state)
- Scoped automatically
- Supports pseudo-classes, media queries, nesting
- Great developer experience (autocompletion)
Cons:
- Extra runtime overhead (small)
- Slightly larger bundle
Install styled-components:
|
0 1 2 3 4 5 6 |
npm install styled-components |
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import styled from 'styled-components'; const Button = styled.button<{ $variant?: 'primary' | 'secondary' }>` padding: 12px 24px; font-size: 18px; border: none; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; background-color: ${props => props.$variant === 'secondary' ? 'transparent' : '#646cff'}; color: ${props => props.$variant === 'secondary' ? '#646cff' : 'white'}; border: ${props => props.$variant === 'secondary' ? '2px solid #646cff' : 'none'}; &:hover { background-color: ${props => props.$variant === 'secondary' ? '#646cff' : '#535bf2'}; color: white; transform: translateY(-2px); box-shadow: 0 4px 12px rgba(100, 108, 255, 0.4); } `; function StyledComponentsDemo() { return ( <div style={{ padding: '40px', display: 'flex', gap: '20px' }}> <Button>Primary</Button> <Button $variant="secondary">Secondary</Button> </div> ); } |
With theme (best practice):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import { ThemeProvider } from 'styled-components'; const theme = { colors: { primary: '#646cff', secondary: '#ff6b6b' } }; function App() { return ( <ThemeProvider theme={theme}> <StyledComponentsDemo /> </ThemeProvider> ); } |
4. Tailwind CSS with React (Utility-First – Fastest Modern Way)
Tailwind CSS = utility-first CSS framework. You write styles directly in JSX using class names.
Why Tailwind is exploding in 2026:
- Extremely fast development
- Consistent design
- No more writing CSS files
- Great with TypeScript + Vite
- shadcn/ui, daisyUI, Mantine… all built on Tailwind
Setup in Vite (easiest way):
|
0 1 2 3 4 5 6 7 |
npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p |
Update tailwind.config.js:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** @type {import('tailwindcss').Config} */ export default { content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], } |
Add to src/index.css:
|
0 1 2 3 4 5 6 7 8 |
@tailwind base; @tailwind components; @tailwind utilities; |
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
function TailwindDemo() { return ( <div className="p-10 max-w-4xl mx-auto"> <h1 className="text-4xl font-bold text-indigo-600 text-center mb-10"> Tailwind CSS in React </h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <button className="px-6 py-3 bg-indigo-600 text-white font-medium rounded-lg hover:bg-indigo-700 transition-all duration-300 shadow-lg hover:shadow-xl transform hover:-translate-y-1"> Primary Button </button> <button className="px-6 py-3 border-2 border-indigo-600 text-indigo-600 font-medium rounded-lg hover:bg-indigo-600 hover:text-white transition-all duration-300"> Secondary Button </button> <div className="p-6 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-xl shadow-2xl hover:scale-105 transition-transform duration-300"> <h3 className="text-xl font-bold mb-2">Gradient Card</h3> <p>Hover me!</p> </div> </div> </div> ); } |
Pro tip: Install Tailwind CSS IntelliSense extension in VS Code → autocomplete + hover previews.
Summary – Chapter 18 Key Takeaways
| Method | Best For | Dynamic Styles | Scoped | Pseudo-classes | Bundle Size Impact |
|---|---|---|---|---|---|
| Inline | Quick one-offs, dynamic props | Excellent | Yes | No | Zero |
| CSS Modules | Clean, traditional CSS, big teams | Good | Yes | Yes | Zero |
| Styled-components | Dynamic, themeable, component-scoped | Excellent | Yes | Yes | Small runtime |
| Tailwind CSS | Fast development, consistent design | Good | Yes | Yes | Small (purged) |
My 2026 Recommendation for you:
- Learning/small projects → CSS Modules or Tailwind
- Production apps → Tailwind CSS (fastest & most popular today)
- Need heavy dynamic styles → styled-components
Mini Homework
- Create a beautiful Card component using each method (4 versions)
- Try Tailwind + add hover effects, dark mode toggle
- Bonus: Combine Tailwind + custom theme context
