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.

References

Related Posts