[v4] @apply inside Svelte / Vue <style>
not working as expected
#15205
Replies: 22 comments 30 replies
-
Hey! Check the relevant documentation here: https://tailwindcss.com/docs/v4-beta#using-apply-in-vue-svelte TL;DR: <style>
@import 'tailwindcss/theme' theme(reference);
.red {
@apply text-red-500;
}
</style> |
Beta Was this translation helpful? Give feedback.
-
I also noticed this with Vue. It took me a long time to realize that I need I agree that this doesn't feel intuitive. Adding I hope to improve "quality of life" for v4. :P |
Beta Was this translation helpful? Give feedback.
-
I'm also looking for a solution to this - I appreciate the preferred approach is to use inline classnames but I do end up using @apply across almost all components.... A solution for us few would be nice. |
Beta Was this translation helpful? Give feedback.
-
Anybody wanting a temporary solution that you could in theory, forget about. I wrote this tiny plugin for vite, which auto-injects the required fix into all .vue files, so you don't have to do it manually. Note: Place the plugin as the first 1. Ignore the above, it doesn't work properly with HMR :( |
Beta Was this translation helpful? Give feedback.
-
This is also required for Astro's |
Beta Was this translation helpful? Give feedback.
-
Just attempted to update to tailwind 4 & bumped into this issue when using it with Vue & Nuxt UI 4. |
Beta Was this translation helpful? Give feedback.
-
Here's the docs I wrote for this earlier this week that will be in the v4 docs, including the CSS modules docs since they go into more detail about the same stuff: Vue, Svelte, and AstroVue, Svelte, and Astro support If you're using Tailwind with these tools, we recommend avoiding If you do use <template>
<button><slot /></button>
</template>
<style scoped>
@import "../app.css" reference;
button {
@apply bg-blue-500;
}
</style> Or just use your globally defined CSS variables instead of features like <template>
<button><slot /></button>
</template>
<style scoped>
button {
background-color: var(--color-blue-500);
}
</style> CSS modulesTailwind is compatible with CSS modules and can co-exist with them if you are introducing Tailwind into a project that already uses them, but we don't recommend using CSS modules and Tailwind together if you can avoid it. Scoping concernsCSS modules are designed to solve scoping problems that just don't exist when composing utility classes in your HTML instead of writing custom CSS. Styles are naturally scoped with Tailwind because each utility class always does the same thing, no matter where it's used — there's no risk that adding a utility class to one part of your UI creates some unexpected side effect somewhere else. PerformanceWhen using CSS modules, build tools like Vite, Parcel, and Turbopack process each CSS module separately. That means if you have 50 CSS modules in a project, Tailwind needs to run 50 separate times, which leads to much slower build times and a worse developer experience. Explicit context sharingSince CSS modules are each processed separately, they have no This means features like @import "../app.css" reference;
button {
@apply bg-blue-500;
} Alternatively, you can also just use CSS variables instead of button {
background: var(--color-blue-500);
} I don't really consider this a workaround or anything, this is the API you need to use when you want to reference Tailwind theme variables from a totally disconnected entry point which is how these style blocks work. Imagine you had two main CSS files in your project that looked like this:
Now in some Vue file you do this: <template>
<h1>Hello world</h1>
</template>
<style>
h1 {
@apply text-primary;
}
</style> There's no way to know if that is supposed to be blue or red without loading the relevant theme configuration. So just like in JS when you need to import something to use it, the same thing is true with v4. |
Beta Was this translation helpful? Give feedback.
-
I just found a great example of the very thing I want to avoid by using apply: https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/buttons/Button.svelte This file has a hundred lines of code inside the style tag simply used to define styles. IMO code could be cleaner if they had done it like:
The script tag would look cleaner and smaller, auto complete and tailwind auto-sorting would work better in the <style> tag, developer would be able to selectivly choose where to look for design bugs vs logic bugs. I think most (if not all) of what they are doing with styles in JS there could be easily achived with some @apply css. I know that in the components libraries that I have worked it cleaned up and isolated the styles from the script very effectively @apply is great for components with multiple styles. |
Beta Was this translation helpful? Give feedback.
-
As a Vue developer and working with a very large codebase, I agree with @lucas-subli on the ergonomics of this being less than ideal. I ran into it today and was confused for some time till I found this discussion.
I understand the argument here and it makes sense for these kinds of apps. But at the same time, many apps have a single theme or design token set. Perhaps a compromise here is to keep this behavior as a default but offer a configuration that the dev could set to tell tailwind that we only follow only one theme config, not sure how feasible is that. @import 'tailwindcss';
/* IDK, anything that would let tailwind know to use the existing config for scoped Vue CSS */
/* Maybe possible values are 'default' | 'all' or whatever */
@tailwind-scope 'all'; |
Beta Was this translation helpful? Give feedback.
-
Same issue here with Vue3 only. I started moving all the component css to tailwind classes on elements and it ended up making things messy with elements that have just too many classes in scenarios such as the one described in this thread. It certainly is more rigorous but it ended up hurting code readability and made things worse than they were before. Sadly I've decided to revert back to v3 because of this, until there is a clean solution. |
Beta Was this translation helpful? Give feedback.
-
It seems impossible to update to Tailwind v4 if you’re using Vue 3, Vite, and have a lot of |
Beta Was this translation helpful? Give feedback.
-
That is quite offending. I guess I am stuck on Tailwind v3 on legacy projects.
https://x.com/adamwathan/status/1890404835888910467
|
Beta Was this translation helpful? Give feedback.
-
@adamwathan you say something very interesting earlier:
In JS, there are multiple way to globally import or auto-import things. It looks like most people have only one "theme configuration" and so, need a way to globally import or auto-import it everywhere (incl. scoped CSS). Wdyt about adding a way to do that easily, explicitely in V4? |
Beta Was this translation helpful? Give feedback.
-
@adamwathan You mentioned that using Tailwind within CSS modules isn't recommended, which makes sense from a performance perspective. You also brought up the approach of using TL;DR: Long version:
|
Beta Was this translation helpful? Give feedback.
-
Why enforce your beliefs on tailwindcss users? |
Beta Was this translation helpful? Give feedback.
-
A Vite plugin solution for Svelte that works without importing it a billion times:
import type { Plugin } from "vite";
export default async function SvelteTailwindApply(): Promise<Plugin> {
return {
name: "svelte-tailwind-apply",
api: {
sveltePreprocess: {
style: async ({ content, filename }: { content: any, filename: any }) => {
if (filename.endsWith(".svelte")) {
const newContent = `@import "@app-css" reference;\n${content}`;
return { code: newContent };
}
return { code: content };
},
},
},
}
};
resolve: {
alias: [
{
find: '@app-css',
replacement: resolve(__dirname, 'src/app.css')
},
]
}
It should roughly look like this:
import { sveltekit } from '@sveltejs/kit/vite';
import tailwindcss from "@tailwindcss/vite";
import SvelteTailwindApply from './src/SvelteTailwindApply';
import { defineConfig } from 'vite';
import { resolve } from 'node:path';
export default defineConfig({
plugins: [sveltekit(), tailwindcss(), SvelteTailwindApply()],
resolve: {
alias: [
{
find: '@app-css',
replacement: resolve(__dirname, 'src/app.css')
},
]
}
}); I don't agree that |
Beta Was this translation helpful? Give feedback.
-
Hi agree this is a huge downgrade going from Tailwind v3 to v4. While I do agree the goal of Tailwind is writing the least custom CSS as possible, there are some scenarios where we have absolutely no control and we must override existing CSS coming from other library. I'm giving a simple exemple in our use case in a Svelte app. We have a "FormSelect" component that uses the "Svelecte" library under the hood and update its styling so it matches our need. Moving from Tailwind 3 to 4 forced us to update the component style like so: In my opinion, it was much cleaner and clearer previously. Also, previously we were protected against typo such as |
Beta Was this translation helpful? Give feedback.
-
Hi everyone, As already stated in my previous comment, the real issue is the lake of automated, globally configured, Developing this plugin took quite a bit of effort. If you find it helpful, please consider...
Additionally, I urge @adamwathan to includes this feature in the official |
Beta Was this translation helpful? Give feedback.
-
I feel like I'm nearing the end of my tailwind career. My projects have recently migrated to uno. The company I work for is also planning to migrate to uno. The components we have here are not suitable for continued development with v4. Based on the future of v3 and the incompatibility of v4, we have to leave Tailwind gradually. |
Beta Was this translation helpful? Give feedback.
-
I think the key takeaways from this discussion are reasonably straightforward:
That said, some frameworks face technical constraints due to differences between their internal CSS handling and Tailwind’s design. This has led to a few issues:
I don’t think there’s much more to add beyond these points, and this thread will likely just reinforce them over time. Hopefully, the Tailwind team can provide a clear commitment to one of the possible paths forward:
|
Beta Was this translation helpful? Give feedback.
-
If you are not using // svelte.config.js
const config = {
kit: {
// ...
alias: { '$app.css': './src/app.css' },
},
};
export default config; <style>
@reference "$app.css";
a {
@apply text-red-700;
}
</style> It works without much config, boilerplate, or plugin. It will also help with Tailwind performance. I have created an issue to add this to the SvelteKit template alias. Thumbs-up will be appreciated: |
Beta Was this translation helpful? Give feedback.
-
What is the point of updating a lib and make it worse? Not working even with @reference! Using: nuxt ui v3.1.0 + nuxt. |
Beta Was this translation helpful? Give feedback.
-
What version of Tailwind CSS are you using?
tailwindcss: 4.0.0-beta.2
@tailwindcss/vite: 4.0.0-beta.2
What build tool (or framework if it abstracts the build tool) are you using?
svelte: 5.2.9
sveltekit: 2.8.5
What version of Node.js are you using?
v20.17.0
What browser are you using?
Chrome, Firefox
What operating system are you using?
Ubuntu 24.04
Reproduction URL
Public github:
https://github.com/lucas-subli/svelte-5-tailwind-4-beta
Describe your issue
This code:
Generates this result:

With this error:
@apply
inside svelte<style>
does not work properly.After this PR: #14151
The below will work:
However, flagging the style as global and importing 'tailwindcss' in every component I want to use
@apply
is not a reasonable solution.The PR mentioned above also has a comment stating:
However, this does not seem to work, as seen in the provided reproduction URL, where tailwind is imported by
app.css
and made available through+layout.svelte
— as previously done with tailwind 3 + SvelteKit.Beta Was this translation helpful? Give feedback.
All reactions