Fixed: Tailwind v4 @source Not Detecting Blade Files

The problem: Tailwind v4 is installed correctly and the build runs clean, but almost none of your utility classes actually generate — the page loads with barely any styling.

Environment: Laravel 11.x/12.x, Tailwind CSS 4.x, @tailwindcss/vite plugin, Blade templates, Livewire components mixed in.

The Error

Just like the classic v3 purge issue, this one throws no exception — the build succeeds and produces a suspiciously tiny CSS file:

▲ terminal
$ npm run build

vite v5.4.2 building for production...
✓ 41 modules transformed.
public/build/assets/app-2b8f4d7a.css   3.86 kB │ gzip: 1.05 kB
✓ built in 940ms

// a real utility set with Blade + Livewire views usually lands
// somewhere around 15-30kB — 3.86kB means Tailwind barely
// scanned anything for class names

Why It Happens

Tailwind v4 dropped the JS content array from tailwind.config.js entirely — there often isn't a config file at all anymore. Instead, source detection now happens two ways: automatic heuristic scanning from wherever your CSS entry file lives, plus explicit @source directives you add yourself for anything the automatic scan misses.

The automatic scan is good at finding files near your CSS entry point, but it reliably misses a few categories that are extremely common in a Laravel app:

  1. Blade views living outside the typical scan radius — package views, admin panel views, or anything under vendor/ that renders Tailwind classes (Filament panels, third-party UI packages).
  2. Laravel's own compiled view cache in storage/framework/views/, which won't get picked up automatically, and matters if you're referencing classes conditionally in ways the raw Blade source doesn't show clearly.
  3. Livewire component classes generated inside PHP methods rather than directly in a .blade.php file, since the scanner is looking for files, not evaluated PHP output.
  4. Classes referenced only inside JS/TS files (Alpine.js expressions building class strings, or a JS-driven component) that live in a folder structure the heuristic doesn't traverse by default.

The Fix

Add explicit @source directives in your CSS entry file, right after the Tailwind import, covering every location the automatic scan might miss:

@import "tailwindcss";

@source "../../resources/views/**/*.blade.php";
@source "../../resources/js/**/*.{js,ts,vue}";
@source "../../storage/framework/views/*.php";
@source "../../vendor/filament/**/*.blade.php";

Paths are relative to the CSS file itself, not your project root — this trips people up constantly. If app.css lives in resources/css/, a directive pointing at resources/views needs ../ to climb back out of css/ first.

For any third-party package (an admin panel, a UI kit) rendering Tailwind classes from its own vendor directory, add an explicit @source line pointing straight at that package's Blade views — Tailwind won't infer it from your app structure alone.

Step-by-Step

  1. Run npm run build and check the CSS output size — a file well under 10kB with a real Blade/Livewire app is a strong signal of under-scanning.
  2. Open your CSS entry file and check whether any @source lines exist at all below the @import "tailwindcss"; line.
  3. Add @source directives for resources/views/**/*.blade.php, any JS/TS folders with class strings, and storage/framework/views/*.php.
  4. If you're using Filament, Livewire's own component packages, or any third-party admin/UI package, add a dedicated @source line pointing at that package's vendor/ path.
  5. Double-check every path is relative to the CSS file's own location, not the project root — count your ../ segments against the actual folder depth.
  6. Rebuild and confirm the CSS file size jumps up to a realistic range before redeploying.
⚠ Edge case: if you're building class names dynamically in PHP (like "bg-{$color}-500"), no amount of @source configuration will fix it — the scanner only ever sees literal, complete class strings in the files it reads, never the result of a runtime string concatenation. That's a separate problem from source detection and needs a lookup array or a Tailwind @source inline(...) safelist-style declaration instead, not a broader glob.

Still getting a tiny CSS file after adding your sources? Send me your CSS entry file on the Contact page and I'll help pinpoint what's missing.

Advertisement
Advertisement