Tailwind
In Next.js you add Tailwind by installing three packages, creating tailwind.config.js, adding the @tailwind directives to globals.css, and importing that file in _app.tsx. Astro ships an official integration that does all of that in one command.
Playground note: Tailwind requires its Vite integration to be installed in the project — a single-file
.astropage in StackBlitz cannot load it without the full setup. This lesson is code-only. Copy any snippet to a local project created withnpx create astro@latestand run the steps below to try it live.
Adding Tailwind to Astro
Section titled “Adding Tailwind to Astro”# inside your Astro projectnpx astro add tailwindThe CLI installs @astrojs/tailwind and tailwindcss, creates tailwind.config.mjs, and adds the integration to astro.config.mjs. Accept all prompts.
// astro.config.mjs — after running the commandimport { defineConfig } from 'astro/config';import tailwind from '@astrojs/tailwind';
export default defineConfig({ integrations: [tailwind()],});// tailwind.config.mjs — auto-generated/** @type {import('tailwindcss').Config} */export default { content: ['./src/**/*.{astro,html,js,jsx,ts,tsx,svelte,vue}'], theme: { extend: {} }, plugins: [],};No globals.css import needed — the integration handles that automatically.
Using utility classes in .astro vs React
Section titled “Using utility classes in .astro vs React”// Card.tsx (Next.js + Tailwind)export default function Card({ title, description, featured = false,}: { title: string; description: string; featured?: boolean;}) { return ( <div className={`rounded-xl border p-6 shadow-sm ${ featured ? 'border-indigo-500 bg-indigo-50' : 'border-slate-200 bg-white' }`}> <h2 className="mb-2 text-lg font-semibold text-slate-900">{title}</h2> <p className="text-sm text-slate-600">{description}</p> </div> );}---// Card.astro (Astro + Tailwind)interface Props { title: string; description: string; featured?: boolean; }const { title, description, featured = false } = Astro.props;---<div class:list={[ "rounded-xl border p-6 shadow-sm", featured ? "border-indigo-500 bg-indigo-50" : "border-slate-200 bg-white",]}> <h2 class="mb-2 text-lg font-semibold text-slate-900">{title}</h2> <p class="text-sm text-slate-600">{description}</p></div>The only mandatory change: className becomes class. Everything else — utility classes, responsive prefixes, dark-mode variants, arbitrary values — works identically.
Mixing Tailwind with scoped styles
Section titled “Mixing Tailwind with scoped styles”You can use Tailwind utilities and a <style> block in the same .astro file. This is useful when a component needs a complex selector (e.g., nth-child, ::before) that Tailwind cannot express cleanly.
<section class="py-24 px-6 bg-gradient-to-br from-indigo-600 to-purple-700"> <h1 class="text-4xl font-bold text-white mb-4">Ship faster</h1> <p class="text-indigo-200 max-w-xl">Tailwind utilities + scoped styles in one component.</p></section>
<style> /* Scoped rule for a complex selector Tailwind cannot express */ section > *:not(:last-child) { margin-bottom: 1rem; }</style>Tailwind and framework components (React / Vue inside Astro)
Section titled “Tailwind and framework components (React / Vue inside Astro)”Utility classes also work on framework components rendered inside Astro pages. Pass classes as class on the Astro wrapper or as className inside JSX if you are inside a .tsx Island component.
---import Counter from './Counter.tsx';---<!-- Tailwind class on the Astro element wrapper --><div class="max-w-screen-lg mx-auto px-4"> <!-- className inside the React Island --> <Counter className="mt-8" client:visible /></div>