Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

@applyBroken in Tailwind CSS v4.0 – No Clear Fix or Docs! #16346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JaquesBotha opened this issue Feb 7, 2025 · 25 comments
Closed

@applyBroken in Tailwind CSS v4.0 – No Clear Fix or Docs! #16346

JaquesBotha opened this issue Feb 7, 2025 · 25 comments

Comments

@JaquesBotha
Copy link

Tailwind CSS v4.0 @apply Bug Report

Introduction

I'm in the process of upgrading a large project, actually, five Blazor projects that all conjoin into one via components and different backends. Our focus with this project is to deliver an optimal UI experience to the end-user, which is why we use TypeScript, C#, and of course, our favorite, Tailwind CSS. Btw, huge fans!

Now, with that said, we have certain native components where we cannot add CSS classes to the component itself, making @apply an essential part of our workflow. However, after upgrading to Tailwind CSS v4.0, @apply is no longer working as expected, and there seems to be little guidance on how to transition projects that rely on it. This bug report aims to outline the issue clearly and request either a fix or detailed documentation on what exactly we need to do to overcome this.

What version of Tailwind CSS are you using?

v4.0.0

What build tool (or framework if it abstracts the build tool) are you using?

Webpack 5.97.1

What version of Node.js are you using?

v20.11.1

What version of npm are you using?

v10.7.0

What IDE are you using?

Rider IDE

What operating system are you using?

macOS

Reproduction URL

There's an active discussion on this issue where many developers are experiencing the same problem but no one has officially reported it yet. Rather than debating, I’d rather get a solution, so here’s the link to the discussion: #13336 (comment)(https://github.com/yourusername/tailwind-v4-apply-issue)

Describe your issue

After upgrading to Tailwind CSS v4.0, I encountered the following issues:

1. @apply Directive Not Functioning

  • The @apply directive, previously used extensively in our CSS for class composition, no longer functions as expected.

  • Example:

    .quickgrid thead th {
        @apply tw-bg-slate-100 dark:tw-bg-slate-800/70 tw-py-4;
    }
    • This results in build errors indicating unknown utility classes such as:
    Error: Cannot apply unknown utility class: tw-transform
    Error: Cannot apply unknown utility class: tw-table-auto
    

2. Lack of Clear Documentation for @apply Usage in v4.0

  • The v4.0 documentation does not provide explicit guidance on how to use the @apply directive in non-Vue projects.
  • One part of the documentation states that @apply should still work, but this is only relevant for Vue projects.
  • Another section in the documentation (CSS Modules Compatibility) suggests using CSS variables instead:
    background: var(--color-blue-500);
    • This is not an ideal solution because it significantly increases the workload, especially in large projects where @apply is heavily used.

3. Backward Compatibility with tailwind.config.js

  • The tailwind.config.js file appears to be deprecated or its usage has changed in v4.0 without clear documentation.
  • Projects relying on configurations such as prefix: 'tw-' are experiencing issues with styles not applying correctly.

4. @apply is Necessary for Native Blazor QuickGrid Components

  • In my case, I use @apply with Native Blazor QuickGrid components, where there is no alternative way to apply Tailwind classes.
  • The current documentation does not provide any solutions for frameworks outside of Vue.

Expected Outcome

  • A fix for @apply so that it functions as expected in Tailwind CSS v4.0.
  • Clear documentation outlining the necessary steps to transition existing projects that rely on @apply.
  • An explicit guide on how tailwind.config.js should be updated for v4.0.

Thank you for your attention to this issue!

@lightify97
Copy link

@JaquesBotha having the same issue. It's a really frustrating experience.

@lightify97
Copy link

@adamwathan

@JaquesBotha
Copy link
Author

Right on! Its like the 4.0 shift was rushed. Too many major changes without proper testing

@lightify97
Copy link

@JaquesBotha I think going back to V3 is the best choice here.

@adamwathan
Copy link
Member

We missed the prefix changes in the upgrade guide, will make a note to add that. The automated upgrade tool should handle those changes for you though if you haven't tried it.

The main difference is prefixes look like variants now and always go at the beginning:

  .quickgrid thead th {
-     @apply tw-bg-slate-100 dark:tw-bg-slate-800/70 tw-py-4;
+     @apply tw:bg-slate-100 tw:dark:bg-slate-800/70 tw:py-4;
  }

Here's the general documentation for the prefix option:

https://tailwindcss.com/docs/styling-with-utility-classes#using-the-prefix-option

I'm not sure how Native Blazor QuickGrid components work but if the CSS for each component is bundled individually the way CSS modules/Svelte/Vue/Astro style blocks are, you may also need to use the @reference option to make sure your theme variables are imported in the right scope:

https://tailwindcss.com/docs/functions-and-directives#reference-directive

Quick search makes me suspect this may be the case because of this CSS isolation functionality, which implies every stylesheet is processed independently with no knowledge of any other stylesheets.

@TGlide
Copy link

TGlide commented Feb 7, 2025

its also happening with me, without prefixes. Using Svelte

@JaquesBotha
Copy link
Author

Response to Tailwind Developer on @apply and Blazor Compatibility

Hey there,

Thanks for the response! I appreciate the clarification on the prefix changes, and I see how that aligns with the new variant structure. That said, the prefix change is really just a small part of the bigger issue I'm facing with Tailwind v4.0 in a Blazor Server environment.

Blazor Is Not Vue (Or Other Scoped CSS Environments)

I noticed in your response that you referenced Blazor QuickGrid's CSS isolation as being similar to how Vue, Svelte, and Astro process styles. However, this assumption isn't entirely accurate for Blazor Server (which is what I'm using) in conjunction with Webpack, TypeScript, and PostCSS.

  • In Blazor Server, we do not have component-scoped styles the way Vue, Svelte, or Astro do.
  • CSS files are bundled traditionally via Webpack/PostCSS, meaning every Tailwind utility class should be accessible globally unless something is actively blocking them.
  • There’s no automatic "style scoping" in Blazor Server that would prevent @apply from working. In fact, @apply has worked flawlessly in previous versions of Tailwind, making this a regression rather than a Blazor-specific issue.

Why @reference Isn’t a Solution Here

I’ve already tried using @reference as suggested, but it does not resolve the issue. If Blazor Server worked like Vue, I would expect:

  1. Tailwind to correctly apply styles within each scoped CSS file.
  2. A missing reference to cause an explicit error, rather than breaking @apply entirely.

Neither of these behaviors are happening. Instead, @apply is failing even in cases where the styles should be globally accessible.

What I Need from Tailwind

Rather than focusing on workarounds (like @reference or changing the prefix), I need a clear explanation of why @apply is breaking even in non-scoped, globally processed CSS.

  • Is this an intentional limitation in Tailwind v4.0, or an unintended side effect?
  • If this is an intended change, what is the exact migration path for users who rely on @apply in a global CSS setup?
  • If this is a bug, what information do you need to reproduce and resolve it?

Again, I really appreciate the work the Tailwind team is doing. I just want to make sure that this upgrade doesn’t break workflows that were previously supported—especially in frameworks like Blazor Server where @apply is an essential tool.

Looking forward to your insights!

@adamwathan
Copy link
Member

@JaquesBotha If the CSS is truly one global stylesheet (all of the stylesheets from your components are concatenated into a single stylesheet before being passed to Tailwind for processing) then everything should work exactly as it did before.

The key thing to understand is for things like @apply bg-red-500 to work, --color-red-500 needs to be defined as a theme variable. In v3 and earlier, the tailwind.config.js file was an assumed convention, and even though scoped styles were all processed independently in v3 as well, we could automatically pick up that config file for each independently processed stylesheet by convention alone.

In v4 with configuration moving to CSS, we can't make assumptions about what your CSS file is called or where it lives, so if you have custom configuration in one CSS file that you need available in another CSS file, you need to explicitly import it using @reference, just like you how you import functions in other programming languages.

So the issue isn't to do with "scoping" it's just whether the CSS is actually processed together as one big stylesheet, or if each stylesheet is being processed one by one without the rules from the other stylesheets being present.

Imagine you have these two stylesheets:

/* one.css */
@import "tailwindcss";

@theme {
  --color-potato: #d2a062;
}

/* two.css */
.foo {
  @apply bg-potato;
}

If these files are conceptually processed independently, sort of like this:

npx @tailwindcss/cli -i one.css -o one.dist.css
npx @tailwindcss/cli -i two.css -o two.dist.css

...you'll get an error when compiling two.css because --color-potato does not exist. It's as if the files are on totally separate computers, there is nothing linking them if they are compiled separately.

This however of course will work fine:

/* everything.css */
@import "tailwindcss";

@theme {
  --color-potato: #d2a062;
}

.foo {
  @apply bg-potato;
}
npx @tailwindcss/cli -i everything.css -o everything.dist.css

...because now --color-potato is defined since it's all one build.

Imagine you had one project that had a client.css file for the client and an admin.css for your internal backed, and both of them defined a custom --color-primary:

/* client.css */
@import "tailwindcss";

@theme {
  --color-primary: blue;
}


/* admin.css */
@import "tailwindcss";

@theme {
  --color-primary: red;
}

Now you have some other component CSS file like this:

/* foo.css */
.foo {
  @apply bg-primary;
}

Is that supposed to be blue or red? It's impossible to know because the color isn't defined and we have no way of making any assumption about what it should be. We could in v3 because of the global tailwind.config.js file, but again in v4 there's no concept of a magic autodetected primary CSS file to automatically use as the context for every other CSS file in the project.

But you're saying that the CSS is global and they aren't processed independently, so what do you mean exactly when you say "@apply is breaking"? Is there an error message? What does the error say?

If you can provide a reproduction we can boot up a Windows environment and take a look. It might be a bug if the CSS truly is all concatenated together and processed as one stylesheet but the fact that @apply isn't working really makes me think Blazor is processing each stylesheet independently.

@codepilotsf
Copy link

In Rails, with v4, we get a stylesheets/application.css and a tailwind/application.css. All @apply directives in my stylesheets/application.css are silently ignored. They just don't do anything. Using @apply in my tailwind/application.css works as expected.

@mohamad68
Copy link

mohamad68 commented Feb 8, 2025

I have dozens of Vue components with @apply in the <style> tags. I tried adding @import and @reference, but it's still not working. It should either restore @apply support without needing any extra imports or automatically upgrade and handle @apply to make it work again.

@adamwathan
Copy link
Member

I have dozens of Vue components with @apply in the <style> tags. I tried adding @import and @reference, but it's still not working. It should either restore @apply support without needing any extra imports or automatically upgrade and handle @apply to make it work again.

@mohamad68 Can you please provide a reproduction? Here's a Vue + v4 project where it is working as expected:

https://github.com/adamwathan/vue-v4-apply

@neonelemental
Copy link

neonelemental commented Feb 9, 2025

@adamwathan That's actually broken, but it's a subtle difference to what you've got here that produces the issue. I'm not sure exactly what the issue is, but if you render a component with the @reference and @apply rather than doing it in App.vue, you'll see that @apply is not working in the component context.

To reproduce the error in your example app, I made the following changes:

// in App.vue

<script setup>
import TestComponent from './components/TestComponent.vue'
</script>

<template>
  <div>
    <TestComponent/>
  </div>
</template>
// in components/TestComponent.vue

<template>
    <h1 class="test">
        Test
    </h1>
</template>

<style scoped>
@reference '../style.css'

.test {
    @apply text-red-500 text-4xl;
}

// or this, which didn't work for me either...

h1 {
   @apply text-red-500 text-4xl;
}
</style>

The result is that the text in the h1 is neither large nor red as I specified in the @apply statement.

@neonelemental
Copy link

@adamwathan Hmm, I toyed around with this and it's kind of flakey. I played around some more with this and got the applies to work copy-pasting your example applies. I'm not really sure what's going on there, but I can confirm I have seen this both not work and work.

I don't know if there's something going on with vite, but when I pulled this down and added the above code, it did not work. At some point I moved some files around and copy-pasted code, and it started working and I was unable to reproduce what I was originally seeing (small, black text instead of 4xl red text)

@neonelemental
Copy link

I'm not 100% sure what the intended behavior is for @apply, I'm just started using tailwind on a personal project and have only ever used tailwind 4. Here's what I am observing. If I comment out the applies in App.vue and add the component for TestComponent, it will render the basic black text. Once I uncomment the App.vue references, all the sudden things start working again, but then I cannot change colors.

My advice would be to take 2 components and add @reference and @apply and start making changes:

  1. Try changing one to blue, one to red
  2. Try changing one to using a class definition and one to using an element definition
  3. Comment things out and uncomment things.

I can't get it to behave consistently at all, and it definitely feels like <style scoped> is not working, because to me it seems like they're interfering with each other, which you would not really expect.

@loukamb
Copy link

loukamb commented Feb 10, 2025

I can also attest that my website (using Astro) has broken in a re-deployment that installed the latest minor version of Tailwind (worked fine on 4.0.3, has problems on latest). Despite no code changes on my end, variables in non-root stylesheets such as var(--text-3xl) simply ceased to exist after the minor update, even though I inserted a @reference statement at the top of said stylesheets to make sure that statements such as @apply text-3xl would receive styling. This pretty much broke my entire blog layout, as well as the layout of two other sites I am also maintaining.

I find it quite impressive that a project as large as Tailwind wasn't able to catch a significant regression in a minor version update (as stated above, it worked fine on 4.0.3, but broke on latest). I am not alone in finding the Tailwind 4.0 "improvements" to be more providing of frustration than anything else, even after consulting the documentation and following the upgrade process correctly. Apparently, my patience in upgrading correctly has been punished with 4.0 minor updates randomly breaking my website if I dare re-deploy.

For now, I will mitigate these problems by pinning my dependencies to 3.0 for each of the projects mentioned above. I would consider re-categorizing 4.0 as a beta (again) until it becomes appropriate for production use.

@JaquesBotha
Copy link
Author

@JaquesBotha If the CSS is truly one global stylesheet (all of the stylesheets from your components are concatenated into a single stylesheet before being passed to Tailwind for processing) then everything should work exactly as it did before.

The key thing to understand is for things like @apply bg-red-500 to work, --color-red-500 needs to be defined as a theme variable. In v3 and earlier, the tailwind.config.js file was an assumed convention, and even though scoped styles were all processed independently in v3 as well, we could automatically pick up that config file for each independently processed stylesheet by convention alone.

In v4 with configuration moving to CSS, we can't make assumptions about what your CSS file is called or where it lives, so if you have custom configuration in one CSS file that you need available in another CSS file, you need to explicitly import it using @reference, just like you how you import functions in other programming languages.

So the issue isn't to do with "scoping" it's just whether the CSS is actually processed together as one big stylesheet, or if each stylesheet is being processed one by one without the rules from the other stylesheets being present.

Imagine you have these two stylesheets:

/* one.css */
@import "tailwindcss";

@theme {
--color-potato: #d2a062;
}

/* two.css */
.foo {
@apply bg-potato;
}
If these files are conceptually processed independently, sort of like this:

npx @tailwindcss/cli -i one.css -o one.dist.css
npx @tailwindcss/cli -i two.css -o two.dist.css

...you'll get an error when compiling two.css because --color-potato does not exist. It's as if the files are on totally separate computers, there is nothing linking them if they are compiled separately.

This however of course will work fine:

/* everything.css */
@import "tailwindcss";

@theme {
--color-potato: #d2a062;
}

.foo {
@apply bg-potato;
}

npx @tailwindcss/cli -i everything.css -o everything.dist.css

...because now --color-potato is defined since it's all one build.

Imagine you had one project that had a client.css file for the client and an admin.css for your internal backed, and both of them defined a custom --color-primary:

/* client.css */
@import "tailwindcss";

@theme {
--color-primary: blue;
}

/* admin.css */
@import "tailwindcss";

@theme {
--color-primary: red;
}
Now you have some other component CSS file like this:

/* foo.css */
.foo {
@apply bg-primary;
}
Is that supposed to be blue or red? It's impossible to know because the color isn't defined and we have no way of making any assumption about what it should be. We could in v3 because of the global tailwind.config.js file, but again in v4 there's no concept of a magic autodetected primary CSS file to automatically use as the context for every other CSS file in the project.

But you're saying that the CSS is global and they aren't processed independently, so what do you mean exactly when you say "@apply is breaking"? Is there an error message? What does the error say?

If you can provide a reproduction we can boot up a Windows environment and take a look. It might be a bug if the CSS truly is all concatenated together and processed as one stylesheet but the fact that @apply isn't working really makes me think Blazor is processing each stylesheet independently.

Response to Adam - Clarifying Blazor Server and @apply

Hey Adam,

I really appreciate the detailed response! However, I want to clarify some misconceptions about how Blazor Server works, particularly in my setup, which uses Webpack + PostCSS to process Tailwind CSS globally within a JavaScript bundle (bundle.js), not a separate global.css file.

1. Blazor Server Does NOT Process CSS Like Vue, Astro, or Svelte

  • You're assuming that Blazor processes CSS in isolated scopes per component, similar to Vue’s scoped styles.
  • This is incorrect in my case because:
    • Blazor does not auto-scope CSS unless explicitly using Blazor CSS isolation (which I am not).
    • All styles are bundled into a single JavaScript file (bundle.js) via Webpack + PostCSS, meaning @apply should be available project-wide.

2. My Tailwind CSS is Processed as Part of bundle.js

  • You gave an example where one.css and two.css are processed separately, requiring @reference.
  • This does not apply to my setup because my Tailwind styles are compiled together into bundle.js via Webpack.
  • If styles were processed independently, all Tailwind utilities would break, not just @apply.

3. @reference Should Not Be Required

  • @reference is only necessary if stylesheets are compiled separately and need explicit imports.
  • Since my entire Tailwind configuration is already applied globally via Webpack/PostCSS and bundled into bundle.js, @reference should be irrelevant in this case.

4. The Real Issue: @apply is Failing Even When Global Styles Are Present

  • The problem isn’t scoping, but rather that Tailwind v4 no longer recognizes @apply correctly in this setup.
  • Example:
    .quickgrid thead th {
        @apply tw-bg-slate-100 dark:tw-bg-slate-800/70 tw-py-4;
    }
    • This results in:
    Error: Cannot apply unknown utility class: tw-transform
    Error: Cannot apply unknown utility class: tw-table-auto
    
    • If Tailwind was truly processing my CSS separately, then normal utility classes wouldn't work either—but they do.

5. Additional Clarity on My Webpack Configuration

Here’s how my Webpack setup ensures Tailwind is globally available:

const path = require("path");

module.exports = {
    mode: "development", // Change to 'production' for production builds
    entry: "./src/index.ts",
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: "ts-loader",
                exclude: /node_modules/
            },
            {
                test: /\.js$/, // Handle .js files
                include: /node_modules\/intl-tel-input/, // Specifically include intl-tel-input JS files
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: ["@babel/preset-env"]
                    }
                }
            },
            {
                test: /\.css$/,
                use: ["style-loader", "css-loader", "postcss-loader"]
            }
        ]
    },
    resolve: {
        extensions: [".tsx", ".ts", ".js"]
    },
    output: {
        filename: "bundle.js",
        path: path.resolve(__dirname, "wwwroot/js")
    },
    watchOptions: {
        aggregateTimeout: 300, // Delay rebuild (optional)
        poll: 1000 // Check for changes every second
    }
};

6. My @apply Code for Clarity

.quickgrid {
    @apply tw-table-auto tw-w-full;
}

/* Table Header */
.quickgrid thead th {
    @apply tw-bg-slate-100 dark:tw-bg-slate-800/70 tw-py-4;
}

.quickgrid th:first-child {
    @apply tw-rounded-s-lg;
}

.quickgrid th:last-child {
    @apply tw-rounded-e-lg;
}

.quickgrid th .col-title-text {
    @apply tw-font-medium tw-text-slate-500 dark:tw-text-slate-300 tw-leading-none tw-text-sm;
}

Next Steps: Is This a Bug or an Intended Change?

Given that my Tailwind CSS is processed globally within bundle.js, I need to understand:

  • Is @apply fundamentally broken in Tailwind v4 for setups using Webpack/PostCSS?
  • If this is an intentional change, what is the migration path for projects like mine?
  • If this is a bug, what information do you need to reproduce it?

I’d really appreciate your insight on this, and if needed, I can provide more details on my build setup.

Thanks again for your time!

@JaquesBotha
Copy link
Author

Follow-Up on Tailwind v4 @apply Issues Across Frameworks

Hey everyone,

Seeing a lot of similar reports here from different frameworks—Rails, Vue, Astro, and my own case with Blazor + Webpack/PostCSS. This makes it clear that @apply in Tailwind v4 isn't just causing issues in one specific environment, but rather across multiple setups.

A few key observations from this thread so far:

  1. Workarounds like @reference do not fully resolve the issue in many cases. If @apply is still supposed to work as expected, it’s unclear when @reference is actually required vs. when it shouldn’t be needed.

  2. Some users (including myself) have global styles processed together in a single build, yet @apply is still failing with "unknown utility class" errors. This contradicts the assumption that styles are being processed independently.

  3. The lack of clarity in the documentation is making upgrades difficult—it’s unclear whether this is an intentional change or an unintended regression.

It would be really helpful to get an official statement from Tailwind on:

  • Whether @apply is still expected to work in all frameworks and setups without requiring additional configuration.
  • If there are new constraints on @apply, what the recommended migration path is.
  • Whether these reports indicate an actual bug.

At this point, it seems like there needs to be a more structured response from Tailwind addressing all of these concerns. Thanks to everyone who's been investigating this, looking forward to some clarification!

Huge fan of Tailwind! Not knocking them down in any way, just trying to help improve things and ensure smooth upgrades for everyone.

@adamwathan
Copy link
Member

@JaquesBotha I think the only logical next step here is to provide a minimal reproduction so we can investigate. I know you are producing global CSS at the end of the day but I still really suspect that each CSS file is being processed as a separate entry point, not that they are scoped in the way CSS modules are or anything.

If you provide a reproduction we can test this and verify with some basic logging.

Workarounds like @reference do not fully resolve the issue in many cases.

This is something I'd be really curious to see a reproduction for. I have not yet seen a case where @reference doesn't resolve the problem. We also don't consider it a workaround, just like how the import keyword in JavaScript is not a workaround.

@JaquesBotha
Copy link
Author

Hey Adam,

That makes sense. To ensure we're covering all bases, today I'll be spinning up a completely fresh Next.js project using Tailwind v4 to see if @apply behaves as expected outside of my current Blazor/Webpack setup.

If the issue persists in a brand-new Next.js environment, that would strongly suggest this is a Tailwind v4 regression affecting multiple setups. If everything works fine there, then we can narrow it down to something specific in Blazor/Webpack.

I rarely use @apply in my projects, but in this case, with Blazor's native QuickGrid component, I don’t have another viable option to apply Tailwind styles effectively. That’s why this issue is particularly important for my setup.

I'll report back with the findings once the tests are complete and, if needed, provide a minimal reproduction repo for further investigation.

Thanks for the patience—I'll get back to you soon!

@adamwathan
Copy link
Member

I can also attest that my website (using Astro) has broken in a re-deployment that installed the latest minor version of Tailwind (worked fine on 4.0.3, has problems on latest). Despite no code changes on my end, variables in non-root stylesheets such as var(--text-3xl) simply ceased to exist after the minor update, even though I inserted a @reference statement at the top of said stylesheets to make sure that statements such as @apply text-3xl would receive styling. This pretty much broke my entire blog layout, as well as the layout of two other sites I am also maintaining.

@loukamb Thanks for the heads up, we've reverted this for now and pushed out a new patch until we can figure out a solution to this scenario.

I find it quite impressive that a project as large as Tailwind wasn't able to catch a significant regression in a minor version update (as stated above, it worked fine on 4.0.3, but broke on latest). I am not alone in finding the Tailwind 4.0 "improvements" to be more providing of frustration than anything else, even after consulting the documentation and following the upgrade process correctly. Apparently, my patience in upgrading correctly has been punished with 4.0 minor updates randomly breaking my website if I dare re-deploy.

Please don't be an asshole — we work very hard to make Tailwind as robust as possible but we're not perfect and sometimes there's a situation we don't manage to anticipate and account for when working on an improvement. When this happens we work quickly to resolve it (about 42 hours for this one). Constructive good-faith feedback that helps the project is appreciated, but passive aggressive stuff like this isn't welcome.

@adamwathan
Copy link
Member

@JaquesBotha A reproduction using Blazor would be more helpful since that's the issue you are facing. It's not clear to me if you'd tried using @reference as we've suggested either, and I haven't gotten a response on how it doesn't resolve your issue. Again @reference is a real feature of the framework that you are expected to use when referencing theme variables defined in separate CSS entry points.

@JaquesBotha
Copy link
Author

Hey Adam,

I appreciate the follow-up, and I understand why a Blazor-specific reproduction would be helpful. That said, I want to make sure we’re aligned on how my setup actually works, because it seems like there’s a misunderstanding.

  • My setup does not have separate CSS entry points.

    • Everything is compiled into a single global bundle.js via Webpack, including Tailwind.
    • There are no separate CSS files that need @reference to link them together.
  • If @reference is required in Tailwind v4 even for global styles, can you clarify why, if you don't mind?

    • If everything is already compiled together, @apply should work as expected.
    • In previous versions, this was never an issue, so is this an intended change?

That said, I will also look into creating a minimal Blazor-specific reproduction, and I’ll report back with my findings. If the issue persists in that environment as well, that would further suggest a regression in Tailwind v4.

Appreciate your patience, I’ll follow up soon.

@loukamb
Copy link

loukamb commented Feb 10, 2025

Please don't be an asshole — we work very hard to make Tailwind as robust as possible but we're not perfect and sometimes there's a situation we don't manage to anticipate and account for when working on an improvement. When this happens we work quickly to resolve it (about 42 hours for this one). Constructive good-faith feedback that helps the project is appreciated, but passive aggressive stuff like this isn't welcome.

@adamwathan I apologize! I made that response wayyy late at night because a team at work called me about this issue (called at 1 am, reply made here at 3 am) when a deployment randomly broke. I subsequently noticed that all two of the projects we are using Tailwind on were broken, which I initially blamed on us until I saw my blog was also broken which frustrated me heavily. When I found out what caused the issues after a couple hours my combined frustration and tiredness wrote that reply.

That said, this morning I was able to "fix" (I don't know if this actually a fix/the proper way of achieving this) the issue by changing @reference statements to @import statements. This means tailwindcss is now imported in every style block, which I don't know if it's the proper way to do this, but it temporary fixes the issue on the latest version of Tailwind. I didn't consider dependency pinning a proper solution so this works for now.

@adamwathan
Copy link
Member

adamwathan commented Feb 10, 2025

Hey Adam,

I appreciate the follow-up, and I understand why a Blazor-specific reproduction would be helpful. That said, I want to make sure we’re aligned on how my setup actually works, because it seems like there’s a misunderstanding.

  • My setup does not have separate CSS entry points.

    • Everything is compiled into a single global bundle.js via Webpack, including Tailwind.
    • There are no separate CSS files that need @reference to link them together.
  • If @reference is required in Tailwind v4 even for global styles, can you clarify why, if you don't mind?

    • If everything is already compiled together, @apply should work as expected.
    • In previous versions, this was never an issue, so is this an intended change?

That said, I will also look into creating a minimal Blazor-specific reproduction, and I’ll report back with my findings. If the issue persists in that environment as well, that would further suggest a regression in Tailwind v4.

Appreciate your patience, I’ll follow up soon.

@JaquesBotha Have you proven that the CSS files aren't processed independently? I would love to see a reproduction.

Unless you have one stylesheet like main.css that explicitly imports all of the other CSS files, I highly suspect that webpack is processing them separately. It doesn't matter if you are only producing a single bundle.js file, that's not relevant to whether the CSS files will be processed separately or not.

In this example for instance both of these CSS files will be run through PostCSS totally separately by webpack:

// main.js
import "stylesheet-1.css";
import "stylesheet-2.css";

// ...

In order to make webpack process them as one, you need to do this instead:

// main.js
import "all-stylesheets.css";

// ...
/* all-stylesheets.css */
@import "stylesheet-1.css";
@import "stylesheet-2.css";

Webpack may be producing one bundle at the end of the day but that is orthogonal to how it processes your stylesheets.

You can verify this by adding a custom PostCSS plugin to your PostCSS setup that logs the name of the file it's processing:

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss')((root, result) => {
      if (result.opts.from) {
        console.log(`Processing file: ${result.opts.from}`);
      } else {
        console.log('Processing unknown file');
      }
    }),
    "@tailwindcss/postcss",
  ],
};

I did this locally in a Next.js project which proves that PostCSS is running separately for each of those CSS files:

Image

Here's the repo for you to take a look at:

https://github.com/adamwathan/postcss-entrypoints

This is not something we have any control over with Tailwind, it's just how the bundler works. If you want everything to build in one step, you need a single CSS file that imports your other CSS files.

@JaquesBotha
Copy link
Author

JaquesBotha commented Feb 10, 2025

Hey Adam,

I appreciate your patience on this. I’ve gone through the entire upgrade process step by step and documented everything, including the errors encountered. Below is a structured breakdown of what I did and the results.


Upgrade Process:

  1. Attempted Automated Upgrade:
    • Ran npx @tailwindcss/upgrade@next.
    • Received a bunch of errors that don’t make sense, and the documentation does not explain them.

Image

  1. Performed Manual Upgrade:

    • Installed the latest versions using:
      npm install tailwindcss@latest postcss@latest autoprefixer@latest
    • Verified that Tailwind updated to v4 in package.json.
  2. Updated postcss.config.js as per documentation:

    • Modified the config file as required:

Image

  1. Updated Tailwind CSS Files:
    • Adjusted tailwind.css, including setting the new prefix (tw- to tw:):

Image

  • Question: Why was the prefix changed? This makes it harder to read. Can we modify this behavior?
  • Included @config to reference the existing Tailwind configuration:

Image

  1. Confirmed Import of Tailwind Styles in index.ts:
    • The index.ts file explicitly imports tailwind.css:

Image

Clarification: Webpack bundles everything here—this is likely where confusion arose earlier. Apologies for not making that clear before.

  1. Ran Webpack Build (webpack --mode development) and Encountered Errors:
    • Received errors related to @apply failing:

Image

  • If I remove all instances of @apply, Tailwind v4 and Webpack work fine.
  • The issue is specific to @apply—even when placed in a separate CSS file, the error persists.

Key Findings:

  • @apply never works in Tailwind v4 with this setup.
  • Removing @apply entirely allows everything else to work fine.
  • This suggests @apply is fundamentally broken in this environment.
  • Normal Tailwind utility classes work as expected, but @apply is consistently rejected.

Next Steps:

I believe this provides enough detail to investigate further. Given that:

  1. Webpack is properly bundling the CSS into a single output.
  2. Normal Tailwind utility classes work fine.
  3. @apply is completely unusable.

This strongly suggests an issue with Tailwind v4’s handling of @apply, not a scoping issue on my end.

Let me know what additional information you need to proceed.

AND again thanks your time appreciate the efforts!

@tailwindlabs tailwindlabs locked and limited conversation to collaborators Feb 11, 2025
@philipp-spiess philipp-spiess converted this issue into discussion #16429 Feb 11, 2025

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants