@apply
Broken in Tailwind CSS v4.0 – No Clear Fix or Docs!
#16429
Replies: 49 comments 52 replies
-
@JaquesBotha having the same issue. It's a really frustrating experience. |
Beta Was this translation helpful? Give feedback.
-
Right on! Its like the 4.0 shift was rushed. Too many major changes without proper testing |
Beta Was this translation helpful? Give feedback.
-
@JaquesBotha I think going back to V3 is the best choice here. |
Beta Was this translation helpful? Give feedback.
-
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 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. |
Beta Was this translation helpful? Give feedback.
-
its also happening with me, without prefixes. Using Svelte |
Beta Was this translation helpful? Give feedback.
-
Response to Tailwind Developer on
|
Beta Was this translation helpful? Give feedback.
-
@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 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 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:
...you'll get an error when compiling This however of course will work fine: /* everything.css */
@import "tailwindcss";
@theme {
--color-potato: #d2a062;
}
.foo {
@apply bg-potato;
}
...because now Imagine you had one project that had a /* 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 But you're saying that the CSS is global and they aren't processed independently, so what do you mean exactly when you 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 |
Beta Was this translation helpful? Give feedback.
-
In Rails, with v4, we get a |
Beta Was this translation helpful? Give feedback.
-
I have dozens of Vue components with |
Beta Was this translation helpful? Give feedback.
-
@mohamad68 Can you please provide a reproduction? Here's a Vue + v4 project where it is working as expected: |
Beta Was this translation helpful? Give feedback.
-
@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 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 |
Beta Was this translation helpful? Give feedback.
-
@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) |
Beta Was this translation helpful? Give feedback.
-
I'm not 100% sure what the intended behavior is for My advice would be to take 2 components and add
I can't get it to behave consistently at all, and it definitely feels like |
Beta Was this translation helpful? Give feedback.
-
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 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. |
Beta Was this translation helpful? Give feedback.
-
I'm working on adding I want to use a prefix like How can I create an alias for my CSS file so that |
Beta Was this translation helpful? Give feedback.
-
if there are no plans to address this issue, someone should close it, and we will proceed to remove @apply file by file from our project |
Beta Was this translation helpful? Give feedback.
-
A few notes what you might be missing out (caused me a lot of headache): When you reference something with: @reference 'path/to/css'
/* don't forget to add semicolon (;) at the end!! it should be like so */
@reference 'path/to/css'; I think something should scream at you (maybe tailwind, that it can't parse those files?) Another thing in Vue that I noticed with scoped styles, you can provide the language like <style lang="postcss" scoped>
/* your styles here with correct reference */
</style> This also breaks the tailwind <style scoped>
/* your styles here with correct reference */
</style> Don't actually know if postcss removal was the problem, but if you're struggling, this might help! |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
So it is still not safe to use |
Beta Was this translation helpful? Give feedback.
-
For someone using multiple CSS files, the @reference crap doesn't even work. |
Beta Was this translation helpful? Give feedback.
-
Tailwindcss just went from best to last with the v4. I mean what in the world were you thinking with going full on CSS? I just tried updating one of our company's demo projects and I had to adjust 250+ Vue components, multiple .less files, remove the tailwind.config.js and I still can not get it to work. And that is a DEMO project. I have lots more (production) waiting on an update. Just the fact that the prefix logic has changed is cumbersome, at least for someone who is not using "tw" as a prefix. Also trying to deprecate a perfect file such as tailwing.config.js to include a GLOBAL config and trying to do the same with @theme directive and CSS variables, which apparently do not work globally anymore and have to be referrenced in each and every file? Man... You're really trying to make it harder to use and of course masively redundant. I will be going back to v3 immediately and if things do not change or adapt in the new version, I might have to think of other options than Tailwind. I can't even imagine who will want to pay for the hours that I'll use to update this blunder in other a lot more massive projects. And again, I can't grasp the idea, that this wasn't a beta, because it should still be in beta testing if you ask me. |
Beta Was this translation helpful? Give feedback.
-
Hi everyone, I just solve this issue for Vue users. Take a look here for details: #15205 (comment) Cheers! 👋🏼 |
Beta Was this translation helpful? Give feedback.
-
Does @reference not work for someone as it does not for me?
The actual button does have a (I'm using "tailwindcss" for the @reference instead of my actual stylesheet as an example because it still doesn't work.) |
Beta Was this translation helpful? Give feedback.
-
V3 was significantly better than this frustrating V4. I maintain multiple Rails/Vue projects, and ever since the upgrade, deployment is completely broken. |
Beta Was this translation helpful? Give feedback.
-
I managed after much pain to migrate to v4 this is the structure I have now /* index.css */
@import url("./checkbox.css");
@import url("./fonts.css");
...
/* Seems important that tailwindcss is imported AFTER other styles */
@import "tailwindcss";
@plugin 'tailwindcss-animate';
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-dark-bg: #141414;
--color-dark-fg: #191919;
--font-inter: "Inter", sans-serif;
...
}
.border-neutral {
@apply border-neutral-300 dark:border-neutral-800;
}
.text-secondary {
@apply text-neutral-600 dark:text-neutral-400;
}
.flex-center {
@apply flex items-center justify-center;
} to use apply in the other files, reference the index /* checkbox.css */
@reference './index.css';
.checkbox__control[data-checked] {
@apply text-neutral-50 border-violet-600 bg-violet-600;
} if you want to use a custom class in an @apply, you need to make it a utility @utility text-primary {
@apply text-neutral-800 dark:text-neutral-200;
}
.other-class {
@apply text-primary w-full;
} |
Beta Was this translation helpful? Give feedback.
-
I can't even build with this simple code.
|
Beta Was this translation helpful? Give feedback.
-
Found a workaround in Nuxt 3+ using Tailwind4 <template>
<div class="list">
Foo Bar
<p>Bar Foo</p>
</div>
</template>
<script lang="ts" setup></script>
<style lang="postcss" src="./chores.css"/> /* <relative to sfc>/list.css */
@reference "../assets/css/main.css";
.-list {
@apply bg-white;
} It would appear the tailwindcss/vite plugin doesn't even look in the Vue files, but if you have a standalone CSS, it's much more forgiving. You'll still have to reference the original css file so it knows what the utility CSS classes are. Completely defeats the purpose of a SFC but if you're in a pinch and need things to work on the newest stuff without an entire rewrite, this might help. Edit (04/06/2025) I removed the "css.lint.unknownAtRules": "ignore", To my settings.json in my VSCode so it doesn't complain about at-rules. Updated my ///...
const mainCssPath = "~/assets/css/main.css";
export default defineNuxtConfig({
//....
vite: {
plugins: [
tailwindcss(),
],
resolve: {
alias: {
"main.css": resolve(dirname(fileURLToPath(import.meta.url)), `./${mainCssPath.replace("~", "")}`)
},
},
},
///...
}); And then I was able to write style tags in my SFCs like... <style scoped>
@reference "main.css";
.chores-list {
@apply bg-white;
}
</style> You'll end up missing some postcss syntax benefits, but I feel like this is the best standing workaround until it is fixed in the official releases. |
Beta Was this translation helpful? Give feedback.
-
I'm not going to lie, like others in this thread, we’ve managed to find a partial workaround. But that doesn’t change the fact that this situation highlights what happens when updates are pushed without proper planning or testing. Version 4 feels like it was rushed out the door, with no clear recourse or rollback strategy for those impacted. What frustrates me most are decisions made without transparent communication or meaningful community input. It doesn’t feel like feedback was considered, or even requested, before shipping breaking changes. I’m a huge fan of Tailwind and have used it extensively. But structure and stability matter. We can’t keep shipping updates that solve one problem but introduce a dozen new headaches. This release seems heavily optimized for frameworks like React, with minimal consideration for broader usage contexts. That’s not acceptable when Tailwind serves such a wide range of developers and platforms. |
Beta Was this translation helpful? Give feedback.
-
Oh and NOT to mention that Tailwind Itellisense plugins in both VS Code and JetBrains (RiderIDE, WebStorm) also STOPPED WORKING all of a sudden! |
Beta Was this translation helpful? Give feedback.
-
Tailwind CSS v4.0
@apply
Bug ReportIntroduction
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 FunctioningThe
@apply
directive, previously used extensively in our CSS for class composition, no longer functions as expected.Example:
2. Lack of Clear Documentation for
@apply
Usage in v4.0@apply
directive in non-Vue projects.@apply
should still work, but this is only relevant for Vue projects.@apply
is heavily used.3. Backward Compatibility with
tailwind.config.js
tailwind.config.js
file appears to be deprecated or its usage has changed in v4.0 without clear documentation.prefix: 'tw-'
are experiencing issues with styles not applying correctly.4.
@apply
is Necessary for Native Blazor QuickGrid Components@apply
with Native Blazor QuickGrid components, where there is no alternative way to apply Tailwind classes.Expected Outcome
@apply
so that it functions as expected in Tailwind CSS v4.0.@apply
.tailwind.config.js
should be updated for v4.0.Thank you for your attention to this issue!
Beta Was this translation helpful? Give feedback.
All reactions