AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Blog
  3. 18 — Styling Next.js — Global CSS, Modules, Tailwind, Sass, CSS-in-JS

18 — Styling Next.js — Global CSS, Modules, Tailwind, Sass, CSS-in-JS

August 13, 20265 min read
Download as Markdown

A styling section that lists five valid options used to read as indecision to me. The model that clicked: all five approaches coexist — global CSS for app-wide rules, CSS Modules for locally-scoped styles, Tailwind for utility-first composition, Sass for preprocessing power, and CSS-in-JS for dynamic theming [1][2][3][4][5]. The choice is less "which is correct" and more "which matches the project's conventions" — Tailwind is the modern default for new work.

Global CSS — the app-wide baseline

Global CSS refers to styles applied across the entire application — a single stylesheet whose rules affect every page unless overridden by more specific rules [1]. In the App Router, a globals.css imported into the root layout establishes the baseline: resets, design tokens, base typography. Global CSS is the right place for things that should be truly universal and the wrong place for component-specific styles.

/* app/globals.css — imported once in the root layout */
@tailwind base;
@tailwind components;
@tailwind utilities;

:root { --color-bg: #ffffff; }
body { background: var(--color-bg); }

CSS Modules — locally scoped by default

CSS Modules locally scope CSS by generating unique class names, so I can use the same class name in different files without collisions [2]. The scoping is automatic — the build turns .button in Button.module.css into something like .Button_button__a1b2c, guaranteeing it won't leak. This is the conventional choice when a project wants component-scoped styles without a utility framework.

// Button.tsx
import styles from './Button.module.css';
export function Button() {
return <button className={styles.button}>Click</button>;
}

Tailwind CSS — utility-first

Tailwind is a utility-first CSS framework: pre-defined utility classes composed directly in markup, instead of writing custom CSS rules [3]. The payoff is rapid UI development and consistent design without context-switching between markup and stylesheets. Tailwind has become the de facto default for new Next.js projects, and create-next-app offers it as a first-class option.

export function Card() {
return <div className="rounded-lg border p-4 shadow-sm">…</div>;
}

The trade-off is the class-name density in markup, which some find noisy. The win is that the design system lives in the config and the utilities, not in ad-hoc CSS files that drift.

Sass — preprocessing power

Sass extends CSS with variables, nesting, mixins, and functions, compiled down to standard CSS [4]. Next.js has built-in Sass support once the package is installed, accepting both .scss and .sass extensions, and component-level Sass via .module.scss. Sass earns its keep in large stylesheets where mixins and nesting reduce repetition; for most modern work, Tailwind and CSS custom properties have absorbed much of that need.

CSS-in-JS — dynamic and co-located

CSS-in-JS writes styles in JavaScript files, using libraries that generate CSS at runtime or build time [5]. The benefits are component-level styling, dynamic theming driven by JS values, and easier CSS dependency management. In the App Router, the constraint matters: because Server Components don't run client-side JS, runtime CSS-in-JS doesn't work in them — the supported approaches are the zero-runtime/build-time ones (e.g., the version of styled-components or Panda CSS that extracts at build). CSS-in-JS is now a deliberate choice rather than the default it once was.

scope: global → component dynamism: static → runtime Global CSS CSS Modules Tailwind Sass CSS-in-JS all five coexist — pick by project convention

How I use this

Tailwind is the default for every new project — the utility-first model, the build-time extraction, and the first-class Next.js integration make it the path of least resistance. Global CSS holds the reset and design tokens. CSS Modules come in when a piece needs scoped styles that don't fit the utility mold. I largely skip Sass (Tailwind covers most of what Sass once solved) and avoid runtime CSS-in-JS in the App Router (Server Components don't run client JS). The principle: pick one primary approach and stick to it; the others are available when a specific need demands them.

References

[1] Vercel, "Global CSS," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/getting-started/css#global-css

[2] Vercel, "CSS Modules," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/getting-started/css#css-modules

[3] Vercel, "Tailwind CSS in Next.js," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/getting-started/css#tailwind-css

[4] Vercel, "How to use Sass in Next.js," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/guides/sass

[5] Vercel, "How to use CSS-in-JS libraries (App Router)," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/guides/css-in-js

[6] Tailwind Labs, "Tailwind CSS," tailwindcss.com, 2024. [Online]. Available: https://tailwindcss.com/

Knowledge check · Question 1 of 5

CSS Modules solve which problem?

Comments

Leave a Comment

You must be signed in to comment

0 Comments

No comments yet. Be the first to comment!