100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
JavaScript

Styling Approaches in Next.js

A practical comparison of the main ways to style Next.js apps: global CSS, CSS Modules, Tailwind CSS, and CSS-in-JS with styled-jsx.

Styling & AssetsBeginner8 min readJul 10, 2026
Analogies

Styling Approaches in Next.js

Next.js does not force a single styling methodology. Out of the box it supports global CSS imported once in the root layout, CSS Modules for component-scoped class names, Tailwind CSS via PostCSS integration, and styled-jsx for CSS-in-JS with zero configuration. Choosing between them usually comes down to team preference, design-system needs, and how much scoping and runtime behavior you want.

🏏

Cricket analogy: Just as a captain like Rohit Sharma chooses between pace and spin depending on the pitch at Chepauk versus the Wankhede, a Next.js team picks a styling approach based on the 'pitch' of their project size and design system needs.

CSS Modules and Global CSS

A file named Button.module.css is automatically scoped by Next.js: class names are hashed at build time so .button in one module never collides with .button in another. Import it as an object — import styles from './Button.module.css' — and apply classes with className={styles.button}. Global CSS, by contrast, can only be imported in app/layout.tsx (App Router) or pages/_app.tsx (Pages Router), not inside arbitrary components, because Next.js needs one predictable place to inject global styles into every page.

🏏

Cricket analogy: CSS Modules scoping is like each IPL franchise having its own numbered jersey system — Mumbai Indians' No. 45 (Rohit Sharma) doesn't clash with Chennai Super Kings' No. 7 (MS Dhoni) because the scope is per-team, just as hashed class names are per-component.

tsx
// app/components/Card.module.css
.card {
  border-radius: 12px;
  padding: 1.5rem;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

// app/components/Card.tsx
import styles from './Card.module.css';

export default function Card({ title }: { title: string }) {
  return (
    <div className={styles.card}>
      <h3>{title}</h3>
    </div>
  );
}

// app/layout.tsx
import './globals.css'; // global CSS only allowed here

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Tailwind CSS in Next.js

Tailwind integrates with Next.js through PostCSS: npx create-next-app offers Tailwind setup during scaffolding, which wires tailwind.config.ts and adds the @tailwind base; @tailwind components; @tailwind utilities; directives to globals.css. The content array in the config tells Tailwind's JIT compiler which files to scan for class names so unused utilities are purged from the production bundle, keeping the final CSS file small regardless of how many utility classes you reference in JSX.

🏏

Cricket analogy: Tailwind's JIT purge is like a franchise's scouting network only keeping players who actually featured in the season's matches on the final squad photo, dropping anyone unused — like Tailwind drops unreferenced utility classes.

Tailwind's JIT engine scans literal class strings at build time, so dynamically constructed names like text-${color}-500 won't be detected. Use complete class names or a lookup map (e.g., a colorClasses object) so Tailwind can find them during the content scan.

CSS-in-JS with styled-jsx

Next.js ships styled-jsx built in, letting you write <style jsx>{...}</style> blocks directly inside a component's JSX; styles are automatically scoped to that component instance via a generated data attribute, and can reference JavaScript values through template literals. Because styled-jsx runs partly at request time in Server Components-friendly ways but historically depends on client-side hydration for dynamic style injection, it works best in Client Components ('use client') rather than as the default for App Router Server Components.

🏏

Cricket analogy: styled-jsx scoping styles per component instance is like a stadium giving each player a wireless earpiece tuned only to their own team's radio channel — Virat Kohli's coach instructions never bleed into the opposition's channel.

styled-jsx requires a 'use client' directive when used inside App Router components that need dynamic, interactive styling — using it in a pure Server Component without that directive can cause hydration mismatches or styles that fail to apply on first paint.

  • Global CSS can only be imported in app/layout.tsx or pages/_app.tsx, never in arbitrary components.
  • CSS Modules (.module.css) auto-scope class names via build-time hashing, preventing collisions across components.
  • Tailwind integrates via PostCSS and create-next-app scaffolding; its JIT compiler purges unused utility classes using the content config array.
  • Tailwind's JIT scanner needs complete, literal class name strings — dynamically interpolated class names are not detected.
  • styled-jsx ships built into Next.js and scopes styles per component instance using a generated data attribute.
  • styled-jsx works best inside Client Components ('use client') due to its reliance on client-side style injection behavior.
  • The right styling approach depends on team size, design-system maturity, and how much runtime dynamism the styles need.

Practice what you learned

Was this page helpful?

Topics covered

#JavaScript#NextJsStudyNotes#WebDevelopment#StylingApproachesInNextJs#Styling#Approaches#Next#CSS#StudyNotes#SkillVeris