Learn Tailwind CSS - Modern Framework Integration & Tooling
Episode 18 of 23

Learn Tailwind CSS - Modern Framework Integration & Tooling

This episode covers Tailwind integration in modern frameworks: Next.js App Router, Vite, SvelteKit, Astro, and Remix, with the patterns and caveats of each. You also learn compatibility with CSS-in-JS using twin.macro and hybrid approaches.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Introduction

Every framework has its own way of handling assets and CSS. Episode 18 covers Tailwind integration in five popular frameworks: Next.js, Vite, SvelteKit, Astro, and Remix — complete with patterns, content paths, and their caveats. You'll also see coexistence with CSS-in-JS.

The core of every integration is the same: Tailwind produces static CSS, and the only difference is where the input file is imported and which files go into content. Once you understand this pattern, moving between frameworks stops being scary.

Next.js App Router

Install Tailwind with PostCSS, then initialize the config:

Setup in Next.js
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Set up content to cover the App Router:

JSContent for Next.js
module.exports = {
  content: ["./app/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx}"],
  theme: { extend: {} },
  plugins: [],
};

Then import the global CSS in the root layout:

JSapp/layout.tsx
import "./globals.css";
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="id">
      <body>{children}</body>
    </html>
  );
}

The pattern content: ["./app/**/*.{js,ts,jsx,tsx,mdx}"] must include .mdx files if you use MDX. Import CSS only in the root layout — not in components — to avoid duplication.

Vite, SvelteKit, Astro, Remix

Vite

Vite provides an official plugin:

Vite plugin for Tailwind
npm install tailwindcss @tailwindcss/vite
JSvite.config.ts
import tailwindcss from "@tailwindcss/vite";
 
export default {
  plugins: [tailwindcss()],
};

This plugin uses Tailwind 4's CSS-first syntax — no longer needing tailwind.config.js for basic cases.

SvelteKit

SvelteKit uses PostCSS. Install, then set the config with content covering .svelte:

JSConfig for SvelteKit
module.exports = {
  content: ["./src/**/*.{html,js,svelte,ts}"],
  theme: { extend: {} },
  plugins: [],
};

Don't forget to add .svelte to the content glob — the most common mistake in Svelte projects.

Astro

Astro also uses PostCSS. Content must cover .astro and .md when used:

JSConfig for Astro
module.exports = {
  content: ["./src/**/*.{astro,html,js,jsx,md,mdx,ts}"],
  theme: { extend: {} },
  plugins: [],
};

Remix

Remix is identical to Next.js: PostCSS, content covering app/**/*.{js,ts,jsx,tsx}, and a global CSS import in the root route.

Info

The most common pattern across every setup: check the framework's file extension list in the content glob. Next.js needs mdx, SvelteKit needs svelte, Astro needs astro and md. One missing extension means classes in those files are never generated.

Compatibility with CSS-in-JS

Tailwind and CSS-in-JS can coexist. A common hybrid approach is twin.macro — using Tailwind utilities inside CSS-in-JS files as a build-time macro:

JStwin.macro + styled-components
import tw from "twin.macro";
 
const Button = tw.button`
  rounded bg-blue-500 px-4 py-2 text-white
  hover:bg-blue-600
`;

tw.button is resolved at build time into plain CSS — no extra runtime from Tailwind. This approach gives you CSS-in-JS ergonomics (scoped, colocated) plus static CSS performance.

An increasingly common alternative: use plain Tailwind in markup and keep CSS-in-JS only for cases that genuinely need runtime logic like dynamic theming. Episode 6 already covered dynamic theming with CSS variables — often that's enough, without any CSS-in-JS at all.

Conclusion

Episode 18 mapped Tailwind integration in modern frameworks: Next.js App Router, Vite, SvelteKit, Astro, Remix, plus coexistence with CSS-in-JS using twin.macro or a lighter hybrid approach.

Key takeaways:

  • All frameworks produce the same static CSS; the only difference is where imports and content point.
  • Next.js: import global.css in the root layout; content covers .mdx.
  • Vite 4 uses the official @tailwindcss/vite plugin.
  • SvelteKit needs .svelte in the content glob; Astro needs .astro and .md.
  • twin.macro combines CSS-in-JS ergonomics with static CSS.
  • CSS variables are often enough for dynamic theming, without CSS-in-JS.

Next, in episode 19, we'll cover component libraries & headless UI patterns — building accessible components with Headless UI, Radix, and Tailwind UI, and documenting components with Storybook.

Learn Tailwind CSS - Modern Framework Integration & Tooling | Learn Tailwind CSS