Errors and fixes

Tailwind: the class is not applied, content, @source and dynamic classes

Tailwind generates only the classes it can read in your files. When one is missing the cause is the scan: wrong path, outside package, runtime string.

Key points

  • In Tailwind 3 the `content` key must list every file that holds classes, including folders outside the root.
  • Tailwind 4 scans on its own, but packages in node_modules must be declared with `@source`.
  • Classes built at runtime exist nowhere as a string in the source, so they are never generated.

Short answer: Tailwind generates only the classes it can read as text in the files it scans. If the class is missing from the CSS, the cause is the scan path or a string built at runtime, not specificity.

Three causes, three checks

CauseHow to recognise itFix
Path not scannedthe class never appears in the generated CSSadd the glob to content (v3) or @source (v4)
Class built at runtimethe full name exists nowhere in the sourcea static class map
File outside the rootworks in dev, fails in the builddeclare the folder explicitly

Tailwind 3: the content key

// tailwind.config.js
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
    "../packages/ui/src/**/*.{js,ts,jsx,tsx}",
  ],
};

The path is relative to the folder of the configuration file, not to the repository root. This is the most common mistake in monorepos: the UI package sits outside and nobody declares it.

Tailwind 4: automatic scanning and @source

@import "tailwindcss";
@source "../node_modules/@acme/ui";
@source "../../packages/www/src";

Tailwind 4 scans from the project root but skips node_modules on purpose. A component library installed from npm must be added with @source, otherwise its classes never reach the CSS.

Dynamic classes

This line does not work, and never will:

The file holds only bg- plus an expression, so Tailwind has no complete string to generate. The fix is an explicit map, which the compiler can also check.

const TONE = {
  danger: "bg-red-500",
  warning: "bg-amber-500",
  ok: "bg-emerald-500",
} as const;

export function Badge({ tone }: { tone: keyof typeof TONE }) {
  return ;
}

When the fix does not work

If the class is in the generated CSS but you cannot see it, the scan is fine: the cause is layer order, a more specific rule that overrides it, or an @apply inside a file imported before Tailwind. Open the Computed panel and look the property up: the answer is there, not in the configuration.

A second edge case is content loaded after the build, for example HTML from a CMS. Tailwind never sees it. Either reuse classes that exist elsewhere in the project, or accept an explicit safelist and measure what it weighs.

How to prevent it

  • Keep classes as string literals: no concatenation, no partial templates.
  • Add a test that builds the production CSS and looks for three critical classes.
  • In a monorepo, declare UI packages once in a shared configuration file.

Where to go next

To build without surprises: components, themes and a pricing block with preview. The guides: dark mode without duplicating the design system and Flexbox and Grid for designers. The comparison: free and premium shadcn themes.

Frequently asked questions

Why does it work in development and not in production?

In development the watcher also sees files outside the build path. In production the CSS is generated once, from the configured paths only.

Should I use safelist?

Only for names you cannot write in full. A safelist grows the CSS and hides the real problem: a class built at runtime.

How does this work in Tailwind 4?

Scanning is automatic across the project. For a library in node_modules you need @source "../node_modules/@acme/ui"; in the CSS file that imports Tailwind.

Is className={ok ? 'bg-red-500' : 'bg-red-100'} generated?

Yes, both strings sit in the source. bg-${color}-500 is not generated, because the file holds only the fragment.

How do I check which CSS was generated?

Build the project and search for the class in the output file. If it is missing, the problem is the scan; if it is there, the problem is specificity or layer order.