Upgrading TailwindCSS to v4 in a Svelte + Vite Environment and Changes in My Perspective on @apply
Introduction
Recently, Tailwind CSS v4 was released.
My portfolio site is built with Svelte (specifically SvelteKit) + Vite and uses Tailwind CSS, so I decided to try upgrading it. Here, I’ll document the upgrade process and share how my perspective on @apply
has changed.
Upgrade Process
There is an upgrade guide available, so I followed it while making necessary adjustments. Some utilities have been deprecated or renamed, so it’s important to be cautious.
First, I ran the official upgrade tool. This tool deletes tailwind.config.js
and modifies app.css
.
npx @tailwindcss/upgrade@next
However, this alone was not sufficient. I continued following the installation guide:
I installed the required plugin using npm install @tailwindcss/vite
and added it to vite.config.ts
.
import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
import tailwindcss from '@tailwindcss/vite'; // Added
export default defineConfig({
plugins: [
sveltekit(),
tailwindcss(), // Added
],
})
At this point, everything should have worked as expected.
Handling @apply
However, when I ran npm run dev
to start the development server, I encountered the error: Error: Cannot apply unknown utility class
. Upon reviewing the upgrade guide, I found that when using @apply
within CSS module files or inside <style>
blocks in Svelte or Vue components, it’s necessary to reference a CSS file that includes @import "tailwindcss";
using @reference
.
Starting from v4, Tailwind’s theme variables, custom utilities, and custom variants are no longer accessible from stylesheets bundled separately from the main CSS file. As a result, explicit references using @reference
are required.
For example, by using @reference
, @apply
can still be used as before:
<div class="text-class">
<p>text</p>
</div>
<style>
@reference "../../styles/app.css";
.text-class {
@apply p-2;
}
</style>
Changes in My Perspective on @apply
Previously, I used @apply
to consolidate Tailwind utility classes, believing it made styling more manageable. However, having to write @reference
every time felt cumbersome, prompting me to reconsider my approach.
As a result, I decided to minimize my use of @apply
. The main reason is that, when components are properly structured, @apply
becomes unnecessary. This perspective was reinforced by the following section from the official documentation, which argues against @apply
. Moreover, Tailwind’s creator, @adamwathan, also recommends using plain utility classes instead of @apply
. I’m inclined to follow this best practice.
Additionally, I found several others advising against @apply
for reasons such as class naming issues, global scope concerns, and increased bundle size. However, in a framework like Svelte with Single File Components (SFCs), naming and scope issues are minimal. Also, for a site of my scale, the increase in bundle size was negligible. That being said, the downsides might not be apparent in my small Svelte site but could become significant in larger applications. Given this, I believe it’s beneficial to get accustomed to a style that doesn’t rely on @apply
, which is another reason I decided to avoid using it.
Conclusion
Despite some challenges, I successfully upgraded my portfolio site to TailwindCSS v4. Moving forward, I plan to manage styles by focusing on component structure and proper prop design rather than relying on @apply
.