On the way to the correct answer, it's worth first clarifying the reason for the existence of @apply and what the main criticism against it is:
Confession: The apply feature in Tailwind basically only exists to trick people who are put off by long lists of classes into trying the framework.
You should almost never use it 😬
Reuse your utility-littered HTML instead.
Source: @adamwathan, #2, #3
<template>
...
</template>
<style scoped>
.my-element {
background-color: var(--bg-red-500);
}
</style>
Basically, it's a fallback for when you can't do things the "proper" Tailwind way. But people tend to abuse it by simply writing CSS the way they always did (component classes in a separate CSS file). They can't get over the fact that Tailwind produces "messy" markup, so they retreat to their CSS file.
Source: Moni
That's the point of Tailwind - to style your elements on your elements, not in a CSS file.
@apply is a stopgap and shouldn't be used more than once or twice per project.
Source: Moni
So whenever possible, this should be avoided. For example, use Tailwind in the traditional way, with utilities in the HTML class attribute. Having many class names is not a problem. Especially with JS frameworks, it's easy to declare a component just once and then reuse it, so there's no code duplication.
Or even better, just use the classes in your markup like you're supposed to
<template>
<div class="bg-blue-500">
<h1 class="mb-2 text-3xl font-bold">Hello world!</h1>
<p>Lorem ipsum dolor sit amet ...</p>
</div>
</template>
Source: @adamwathan
But performance-related reasons can also be cited to argue against its use:
A ton of confusion amongst Tailwind users comes from not realizing
that if you are using CSS modules, or <style> blocks in
Vue/Svelte/Astro, your CSS pipeline separately for every single one of
those blocks.
50 Vue components using <style> means Tailwind runs 50 separate times.
Source: @adamwathan
But if it is still needed, even here it's better to rely on global variables, which Tailwind CSS generates for every value declared in @theme:
For the best build performance, don't use Tailwind features in CSS
modules or Vue/Svelte/Astro blocks, just rely on CSS
variables.
<template>
<div>
<h1>Hello world!</h1>
<p>Lorem ipsum dolor sit amet ...</p>
</div>
</template>
<style>
div {
background-color: var(--color-blue-500);
}
h1 {
font-size: var(--text-3xl);
line-height: var(--text-3xl--line-height);
font-weight: var(--font-weight-bold);
margin-bottom: calc(2 * var(--spacing));
}
</style>
Source: @adamwathan
But in the case of Tailwind CSS, to avoid duplication, it's better to do these in central CSS and then only use that in the local component. This results in much less duplication in the final CSS compared to creating separate CSS per component. Component-specific separated styles generate larger CSS, and although you load it in parts, in many cases you may load the same styling 2x, 3x, or multiple times, which is not very efficient.
The same thing happens by the way by just importing multiple CSS files in JS. Don't do that — import them all into one CSS file and load that one file in JS instead.
Source: @adamwathan
Conclusion
The use of @apply is not recommended for performance and increased production size reasons in separated <style> blocks or CSS modules. If you still need module CSS, reference CSS variables instead of class names to reduce the final size. But it's better to centralize all styling - even if this increases the size of the centralized CSS, it will still be smaller than having many fragmented duplicates.
If you avoid using @apply, the error mentioned in the question cannot occur.
I recommend using utilities more frequently in the HTML. The primary goal of Tailwind CSS is to minimize writing CSS code and creating custom CSS classes, so .header { ... } or other styling has little purpose with Tailwind CSS - it simply goes against the goal: using pre-made utility classes.
Essentially if you ever find yourself doing something like:
.btn {
@apply px-4 py-2 rounded bg-blue-500 text-white;
}
Stop, slap yourself hard, once, and make a <Button> component instead:
<button class="px-4 py-2 rounded bg-blue-500 text-white">
<slot/>
</button>
Source: Moni
css.customDatainjection solves the syntax warning, but I only managed to get it working at the workplace level, which is counterproductive for 50 different projects.@applyin Tailwind v4?@apply- Moni