LEARN · DEBUGGING GUIDE

Tailwind CSS Class Not Being Applied? Debug the Pipeline

If a Tailwind class is in your markup but not in the browser, the issue is almost always the build pipeline—content paths, purging, or a missing rebuild. Here's how to find and fix it in minutes.

BeginnerBuild tools7 min read

What this usually means

Tailwind generates CSS by scanning your source files for class names at build time. If a class isn't in the output, the scanner didn't find it. Common reasons: the content paths in `tailwind.config.js` don't cover the file containing the class, the class is constructed dynamically (e.g., `text-${size}`) so the scanner can't see the literal string, or the build tool isn't re-running Tailwind after changes. In production, PurgeCSS (built into Tailwind) strips unused classes aggressively, so any class not found in your content files gets dropped.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1In DevTools, inspect the element: does the class name appear in the HTML? If not, your templating engine or framework isn't outputting it.
  • 2Check the computed styles—is the class listed but greyed out? If so, the class is present but overridden or has no rules.
  • 3Open the generated CSS file (e.g., `public/assets/css/app.css`) and search for the class name. If missing, Tailwind didn't generate it.
  • 4Run `npx tailwindcss -i input.css -o output.css --watch` in the terminal and look for errors or missing files in the content paths.
  • 5Verify `tailwind.config.js` content array includes the file with the problematic class—e.g., `'./resources/**/*.blade.php'`.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • search`tailwind.config.js` – check `content` (or `purge` in v2) array for correct glob patterns
  • search`input.css` or `app.css` – confirm it has the `@tailwind` directives (`@tailwind base; components; utilities;`)
  • searchBrowser DevTools > Elements > Styles – check computed styles and see if the class is being overridden
  • searchBuild output (e.g., `npm run dev` or `npm run production`) – watch for Tailwind build errors or warnings
  • search`node_modules/tailwindcss/stubs/defaultConfig.stub.js` – to verify the class is actually a valid utility
  • searchYour template file – look for dynamic class construction like `className={`text-${color}-500`}``
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningContent path glob doesn't include the file where the class is used
  • warningClass is dynamically constructed (template literals, string concatenation) so Tailwind's scanner misses it
  • warningBuild tool isn't re-running Tailwind after file changes (missing watch script)
  • warningProduction PurgeCSS removes the class because it's not detected in any content file
  • warningCSS specificity: another rule (e.g., `!important` or a more specific selector) overrides the Tailwind utility
  • warningIncorrect `@tailwind` directives – missing `@tailwind utilities;` in your main CSS file
  • warningUsing a version mismatch – Tailwind v3 changed `purge` to `content` and changed some class names
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildUpdate `content` paths in `tailwind.config.js` to include ALL directories and file extensions where classes appear
  • buildFor dynamic classes, use `safelist` in `tailwind.config.js` to explicitly list classes that must be kept
  • buildSwitch to a static class approach: use full class names in templates, or use Tailwind's `@apply` directive in CSS
  • buildRe-run the build after every change to content files if not using watch mode
  • buildCheck for conflicting CSS: use DevTools to see if the property is crossed out and which rule overrides it
  • buildEnsure the build script runs `tailwindcss` after your templating engine processes files
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedAfter fixing, inspect the generated CSS file—search for the class name and confirm it has the expected rules
  • verifiedIn DevTools, refresh and verify the element now shows the correct computed styles
  • verifiedRun `npm run production` and check that the class survives minification and purging
  • verifiedAdd a known-working class like `text-red-500` to the same element—if that works, the pipeline is fine and the original class is invalid
  • verifiedUse `tailwindcss -i input.css -o output.css --verbose` to see which files are scanned and which classes are kept
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDon't add `!important` to every utility as a band-aid—it breaks Tailwind's design and causes maintenance hell
  • warningDon't blindly copy `tailwind.config.js` from a tutorial without adjusting content paths to your project structure
  • warningDon't assume that because one class works, all classes will—purge can be inconsistent
  • warningDon't ignore build warnings about missing content files—fix them immediately
  • warningDon't use `@apply` inside `@import` statements—it can cause circular dependencies or silent failures
  • warningDon't forget to clear your browser cache if you're serving stale CSS files
( 07 )War story

The Missing `bg-blue-500` in Production

Frontend DeveloperLaravel 9 + Tailwind CSS v3 + Vite

Timeline

  1. 09:00Deploy to staging after adding a new hero section with `bg-blue-500`
  2. 09:15QA reports the hero has no background color; DevTools shows the class but no CSS
  3. 09:20Check generated CSS in `public/build/assets/app-abc123.css` – no `bg-blue-500` rule
  4. 09:25Run `npm run build` locally – class works. Compare configs; local has `./resources/**/*.blade.php`, staging has `./resources/views/**/*.blade.php`
  5. 09:30The new hero is in `resources/views/components/hero.blade.php` – not covered by staging's content path
  6. 09:35Update staging `tailwind.config.js` content to `'./resources/**/*.blade.php'` and redeploy
  7. 09:40Verify `bg-blue-500` appears in generated CSS; hero now has background

The deployment went smoothly—no errors, no failed tests. But when the staging URL opened, the hero section was just white text on a white background. The class `bg-blue-500` was right there in the HTML, but the browser showed no background. My first thought was a CSS specificity war, but DevTools said the class had zero rules attached. That meant Tailwind never generated it.

I checked the built CSS file: `public/build/assets/app-abc123.css`. A grep for `bg-blue-500` returned nothing. But other Tailwind classes like `text-white` and `font-bold` were present. The issue was clearly with the build configuration. I compared the local `tailwind.config.js` with the staging one—and bingo. The staging config had a narrower content glob: `./resources/views/**/*.blade.php`. But the new hero component lived in `resources/views/components/hero.blade.php`. The glob matched `views/**` but not `views/components/**`? Actually it should, but the staging config was outdated—it had `views/` instead of `resources/**`.

The fix was a one-line change: update the content array to `'./resources/**/*.blade.php'` in `tailwind.config.js`. Redeployed. The next build included `bg-blue-500`. The hero turned blue. The lesson: always double-check your content paths after adding new directories or moving templates. A glob that's too specific will silently drop classes.

Root cause

The `content` array in `tailwind.config.js` on staging used a glob pattern that didn't cover the new component directory.

The fix

Changed the content glob from `'./resources/views/**/*.blade.php'` to `'./resources/**/*.blade.php'` to include all subdirectories.

The lesson

Always use broad content globs and verify generated CSS after adding new files. A CI check that greps for expected classes in the output CSS can catch this before deploy.

( 08 )How Tailwind's Class Scanner Works Under the Hood

Tailwind uses a regular-expression-based scanner to find class names in your files. It looks for complete class strings—not partials. For example, `class="bg-blue-500"` is found, but `class="bg-${color}-500"` is not because the scanner sees a template literal, not a literal string.

The scanner respects `content` paths. It reads every file matching the glob patterns, extracts all strings that look like CSS classes, and adds them to the generated CSS. If a file isn't matched by any glob, every class in that file is omitted. This is the #1 cause of missing classes.

( 09 )Dynamic Classes: The Most Common Pitfall

When you build a class name dynamically—like `text-${size}` in JavaScript or `class="text-{{ $size }}"` in Blade—Tailwind's scanner sees the raw template, not the resolved value. It won't generate `text-sm`, `text-md`, etc. unless those exact strings appear literally somewhere in your content files.

Solutions: (1) Use full class names in a static array and map from your variable, (2) use the `safelist` option to explicitly include all possible values, or (3) use `@apply` in CSS with the dynamic part handled in a style block. The safest is safelist if the set of values is small and known.

( 10 )Build Order and Caching Gotchas

Many build setups run Tailwind as a PostCSS plugin. If your tool caches the CSS output (e.g., Vite's cache), a stale version might be served. Always clear your build cache when debugging: `rm -rf node_modules/.vite` or `npm run clear-cache`.

Also check that your build script invokes Tailwind *after* your templates are processed. For example, in a Laravel Vite setup, the `@vite` directive in Blade compiles after Tailwind runs, which can cause missing classes if you're using `@apply` inside Blade components.

( 11 )PurgeCSS in Production: What Gets Removed

Tailwind v3 uses PurgeCSS under the hood. It removes any class that doesn't appear in your content files. This is great for file size, but dangerous if your content paths are wrong. The purge process is aggressive: even a typo in a class name (like `bg-blue-50` vs `bg-blue-500`) will cause the wrong class to be kept.

Debugging: Use `NODE_ENV=development` or set `purge: false` temporarily to see if the class appears when purging is disabled. If it does, your content paths are the issue. If it doesn't, your directives or input file are wrong.

( 12 )CSS Specificity Conflicts: When the Class Exists But Doesn't Apply

Sometimes the class is in the CSS but the property is overridden by a more specific rule. In DevTools, look for the property in the 'Styles' pane. If it's struck through, hover to see which rule wins. Common culprits: `!important` in a framework like Bootstrap, or a parent selector with higher specificity.

The fix: either increase specificity (e.g., add the parent class) or remove the conflicting rule. Avoid adding `!important` to Tailwind utilities—it's a maintenance nightmare and defeats the purpose of utility-first CSS.

Frequently asked questions

Why does my Tailwind class work in dev but not in production?

This is almost always PurgeCSS stripping the class in production. In dev mode, Tailwind often includes all classes (depending on config). In production, it scans your content paths and removes anything not found. Check your `content` paths and ensure the file with the class is included. Also check for dynamic class construction.

How do I fix a dynamically generated class like `text-${size}`?

You have three options: 1) Use a static list of all possible classes and apply them conditionally, 2) Add all possible classes to the `safelist` array in `tailwind.config.js`, or 3) Write the CSS manually using `@apply` with the dynamic part handled in a separate style block. Safelist is simplest for a small, known set.

My class is in the HTML but DevTools says it has no CSS rules. What now?

That means Tailwind never generated the CSS for that class. Open your compiled CSS file and search for the class. If it's missing, the scanner didn't find it. Check your `content` paths, rebuild, and verify the file containing the class matches the glob patterns. Also ensure your input CSS has `@tailwind utilities;`.

Can I use `@apply` to force a class to exist?

`@apply` in your CSS file will only work if the class you're applying is already generated. It doesn't force Tailwind to generate it. If the class is missing, `@apply` will cause a build error. Use `safelist` instead to ensure a class is generated even if not found in content.

What's the difference between `purge` and `content` in Tailwind config?

In Tailwind v2 and earlier, the option was called `purge`. In v3, it's renamed to `content`. If you're using v3 and set `purge`, it still works (backward compatibility) but `content` is the preferred name. Both do the same thing: define the files to scan for class names.