Tailwind Statamic Debugging

Why Your Tailwind Classes Work Locally But Disappear in Production (Statamic Edition)

Interloper Digital 5 min read

Here's a frustrating one. You've got a Statamic site with some conditional styling. Maybe a blur effect that activates based on a toggle field, or a colour class that changes based on content.

Works perfectly in development. You're seeing exactly what you expect. Then you deploy to production and... the styles are gone. The class is there in the HTML, but the CSS rule doesn't exist.

What's happening is a Tailwind gotcha that's particularly sneaky when you're combining it with Antlers templating.


The Problem

Tailwind CSS uses static analysis to determine which classes to include in your production bundle. It scans your files, finds class names, and only includes the CSS for classes it actually sees.

The key word is sees. Tailwind needs to find complete, unbroken class strings in your source files.

When you write something like this in Antlers:

<img class="{{ if blur_image }}blur-md{{ /if }} w-full h-auto">

Tailwind's scanner might not recognise blur-md as a class to include. The conditional Antlers syntax breaks up the string in a way that static analysis can miss.

Development mode is more forgiving—it often hot-reloads and dynamically includes classes as it sees them. Production builds are strict. If the class wasn't found during the build scan, it's not in your CSS bundle.


Why It Happens in Statamic Specifically

This isn't a Statamic bug—it's a Tailwind + dynamic templating interaction. But Statamic makes it particularly easy to hit because:

  1. Antlers syntax is unfamiliar to Tailwind's scanner. It's not looking for {{ if }} blocks the way it might handle React ternaries or Vue bindings.

  2. Content-driven styling is common. Statamic sites often have CMS fields that control visual presentation—toggles for blur effects, selects for colour schemes, conditionals for layout variants.

  3. You're editing .antlers.html files. If your Tailwind config doesn't explicitly include these in its content paths, classes in those files might be missed entirely.


The Fixes

You've got a few options depending on your situation.

Option 1: Safelist the Classes

If you have a small number of conditional classes, add them to your Tailwind config:

// tailwind.config.js
module.exports = {
  safelist: [
    'blur-md',
    'blur-lg',
    'grayscale',
    // Add any classes used conditionally in Antlers
  ],
  // ... rest of config
}

Safelisted classes are always included in the build, regardless of whether Tailwind's scanner finds them.

Option 2: Ensure Antlers Files Are Scanned

Make sure your Tailwind config includes the right file paths:

// tailwind.config.js
module.exports = {
  content: [
    './resources/views/**/*.antlers.html',
    './resources/views/**/*.blade.php',
    './resources/js/**/*.js',
    './resources/js/**/*.vue',
  ],
  // ... rest of config
}

If you're using Tailwind v4 with the new CSS-based configuration, it looks like this in your CSS file:

@source "../views/**/*.antlers.html";

Option 3: Write Complete Class Strings Somewhere

Tailwind just needs to see the class as a complete string somewhere in your scanned files. You can add a comment in your CSS:

/* Conditional classes used in Antlers templates */
/* blur-md blur-lg grayscale opacity-50 */

Or create a safelist file that Tailwind scans:

<!-- resources/views/tailwind-safelist.html -->
<!-- This file exists solely for Tailwind's scanner -->
<div class="blur-md blur-lg grayscale opacity-50 bg-red-500 bg-blue-500"></div>

Just make sure the file is in a path that Tailwind's content config includes.

Option 4: Avoid Dynamic Class Names Entirely

Sometimes the cleanest solution is restructuring your template:

{{# Instead of dynamic class string #}}
<img class="{{ if blur_image }}blur-md{{ /if }}">
{{# Use a wrapper with complete classes #}}
{{ if blur_image }}
    <img class="blur-md w-full h-auto">
{{ else }}
    <img class="w-full h-auto">
{{ /if }}

More verbose, but Tailwind will find both blur-md and the non-blurred version in its scan.


How to Debug This

When a class isn't working in production:

1. Check the built CSS

Open your compiled CSS file (usually in public/build/assets/) and search for the class name. If it's not there, Tailwind didn't include it.

2. Verify your content paths

Run your build and watch for warnings about files not being scanned. Or temporarily add a console.log in your Tailwind config to confirm paths are resolving correctly.

3. Test with safelist

Add the problematic class to your safelist and rebuild. If it works now, you know the issue was class detection, not something else.


Classes That Commonly Hit This

Based on my experience, these are the usual suspects:

  • Effect classes: blur-md, grayscale, sepia, backdrop-blur
  • Conditional colours: bg-{colour} when the colour is content-driven
  • State variants: hover:, focus:, group-hover: when applied conditionally
  • Responsive variants: md:, lg: when the breakpoint-specific class is conditional

Anything where the class appears inside Antlers logic is at risk if Tailwind's scanner doesn't parse Antlers syntax correctly.


Prevention

For future projects, I'd suggest:

  1. Safelist proactively. If you know you'll have CMS-controlled styling, add those classes to your safelist from the start.

  2. Test production builds locally. Run npm run build and check your site with the production CSS before deploying.

  3. Keep conditional classes minimal. The more styling you control via CMS fields, the more safelist maintenance you'll have.


This one bit me on a client project where a blur effect worked perfectly in development for weeks, then vanished the moment we deployed. The fix was a single line in the Tailwind config, but finding the cause took longer than I'd like to admit.

Static analysis tools and dynamic templating don't always play nicely together. Now you know what to look for.

Need Help With Your Frontend?

Book a free Discovery Audit and get expert guidance on your Tailwind and Statamic challenges.

Book a Discovery Audit