Handling Tailwind CSS in Next.js: Common Issues and Practical Solutions
This article explains how to set up Tailwind CSS in a Next.js project, addresses dynamic class name problems, class‑priority conflicts, and provides solutions using tailwind‑merge, clsx, and class‑variance‑authority, along with useful tools and VSCode extensions for smoother development.
Introduction
Tailwind CSS has become a mainstream CSS framework for front‑end development, with over 80k GitHub stars and millions of weekly npm downloads. Next.js scaffolding includes Tailwind by default, allowing developers to start using it immediately. Although Tailwind appears simple, there are hidden pitfalls that this guide will cover, followed by a list of helpful websites and tools.
Project Initialization
Start a fresh Next.js project:
npx create-next-app@latestWhen prompted, enable Tailwind CSS and App Router . Other options can be left at default.
Problem 1: Dynamic Class Names
1. Reproduction
Modify app/page.js to use a static class name:
'use client'
export default function Home() {
return (
Submit
);
}The button renders correctly. Changing the class name to a template literal that depends on a state variable:
'use client'
import { useState } from "react";
export default function Home() {
const [color, setColor] = useState("indigo");
return (
Submit
);
}Even after restarting the dev server, the button appears blank because Tailwind does not generate the bg-indigo-600 utility when the class name is built dynamically.
2. Explanation
Tailwind scans source files for class names using a regular expression. Any string that looks like a class name, even if it is not inside a className attribute, will be considered. Therefore, putting the class name in a variable or in text still makes Tailwind include it, but building the name at runtime prevents detection.
3. Solution
Do not construct Tailwind classes dynamically. Either list all possible classes explicitly, use a safelist in tailwind.config.js , or use a blocklist to exclude unwanted classes.
// tailwind.config.js
module.exports = {
content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
safelist: ['bg-indigo-600'],
blocklist: ['container', 'collapse'],
};Problem 2: Class‑Priority Conflict
1. Reproduction
Component Button defines a base red background, while the parent passes a blue background via className :
function Button({ className }) {
return (
Submit
);
}
export default function Home() {
return
;
}The rendered button is red because Tailwind’s generated CSS order gives higher precedence to the earlier class.
2. Explanation
Class order in the HTML markup does not affect specificity; the order in the compiled CSS does. Tailwind cannot guarantee the desired order when classes are merged.
3. Solutions
3.1 tailwind‑merge
Install tailwind-merge and wrap class names with twMerge() so later arguments win:
npm i tailwind-merge import { twMerge } from 'tailwind-merge';
function Button({ className }) {
return (
Submit
);
}3.2 clsx
Combine clsx with twMerge to handle conditional classes:
npm i clsx import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
function cn(...inputs) { return twMerge(clsx(inputs)); }Now you can write:
className={cn('bg-red-600 w-1/2 p-2 m-2 rounded text-white', className, { 'bg-amber-600': submitting })}3.3 cva (Class Variance Authority)
For complex component variants, install class-variance-authority and define a variant schema:
npm i class-variance-authority import { cva } from 'class-variance-authority';
const button = cva('rounded p-2', {
variants: {
intent: {
default: ['bg-blue-600', 'text-white'],
primary: ['border', 'border-black', 'bg-white', 'text-black'],
dashed: ['border', 'border-dashed', 'border-black', 'bg-white'],
link: ['text-blue-600'],
text: ['text-black'],
},
size: {
small: ['px-2', 'py-2'],
middle: ['px-4', 'py-2'],
large: ['px-6', 'py-2'],
},
},
defaultVariants: { intent: 'default', size: 'middle' },
});
function Button({ type, size }) {
return
Default Button
;
}Useful Websites and Tools
1. Reference Sites
https://tailwindcomponents.com/cheatsheet/
https://tailwind.spacet.me/
CSS‑to‑Tailwind converter: https://www.divmagic.com/zh-CN/tools/css-to-tailwind
2. VSCode Extensions
Tailwind CSS IntelliSense – autocomplete, linting, and preview.
Tailwind Documentation / Tailwind Docs – quick access to official docs.
Tailwind Fold – collapses long class lists for readability.
Prettier Plugin for TailwindCSS – automatically sorts classes. npm install -D prettier prettier-plugin-tailwindcss { "plugins": ["prettier-plugin-tailwindcss"] }
References
https://tailwindcss.com/docs/content-configuration#class-detection-in-depth
https://tailwindcss.com/blog/automatic-class-sorting-with-prettier#how-classes-are-sorted
https://www.youtube.com/watch?v=re2JFITR7TI
https://www.youtube.com/watch?v=guh9qzxkb1o&ab_channel=ByteGrad
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.