Skip to content
Release notesStyling & UI

Tailwind CSS v4 with Vue and Vite: the new setup

Tailwind CSS 4.0 shipped on 21 January. Setting it up in a Vue project is now four short steps, and the config file is gone.

vuejs.school team28 Jan 20256 min readTailwind CSS 4.0 · Vite 6

Tailwind CSS is the utility-class framework: instead of writing CSS rules, you put classes like p-4 and text-lg on elements. Version 4.0 was tagged on 21 January, and the announcement went out the next day. It changes how you install and configure Tailwind more than it changes the classes you type.

For a new Vue project, the setup is now two packages, one plugin in the Vite config and one line of CSS, with no config file. For a v3 project, check browser support first, then run the upgrade tool and read its diff.

What shipped in 4.0

The announcement leads with a new engine: full builds up to 5x faster and incremental builds over 100x faster. The median times behind those claims, measured on the team's own Catalyst project, are more useful:

  • Full build: 378ms in v3.4, 100ms in v4.0.
  • Rebuild that adds new CSS: 44ms to 5ms.
  • Rebuild with no new CSS: 35ms to 192µs.

The 100x figure is that last case: a save that only uses classes you have already used finishes in microseconds.

Four changes affect setup, and each has a section below:

  • A dedicated Vite plugin, @tailwindcss/vite.
  • One @import line instead of three directives.
  • Configuration in CSS with @theme, instead of tailwind.config.js.
  • Automatic detection of template files, with no content array.

Underneath, the engine is built on modern CSS: native cascade layers, logical properties, custom properties registered with @property (CSS variables with a declared type) and color-mix(), which v4 uses for opacity modifiers like bg-blue-500/50. Those last two set the browser floor in the next section.

New in the classes you write:

  • The default palette moves from rgb to oklch, using the wider P3 colour range of modern screens for more vivid colours.
  • Container queries are in core, and there are 3D transform utilities.
  • Linear gradients take angles (bg-linear-45), and radial and conic gradients are new.
  • A starting: variant transitions an element when it first appears, and a not-* variant applies a style when another variant does not match.

Check browser support before you switch

The compatibility page says the core of v4 depends on Chrome 111, Safari 16.4 and Firefox 128. Those are the first versions that support both @property and color-mix(), and v4.0 has no fallback mode for anything older.

Chrome 111 and Safari 16.4 came out in March 2023, Firefox 128 in July 2024, so for most apps built in 2025 those versions are fine. If your users include older corporate desktops or old iPads that cannot update Safari, stay on v3.4 for now: your v3 setup keeps working as it is.

Some utilities, such as field-sizing and the starting: variant, rely on features with limited browser support. Leave those out if the browsers you support lack them.

Install the Vite plugin

Start from a project created with npm create vue@latest, or any Vue and Vite project that does not use Tailwind yet. Install two packages:

npm install tailwindcss @tailwindcss/vite

Then add the plugin to the Vite config. A create-vue project already has vue() and vueDevTools() there, so the new lines are the tailwindcss import and tailwindcss() at the end of plugins:

vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [vue(), vueDevTools(), tailwindcss()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
})

There is no PostCSS config to create and no tailwind.config.js. The announcement says this plugin performs better than the PostCSS one.

Replace main.css with one import

A create-vue project imports src/assets/main.css from main.ts. Replace everything in that file with a single line:

src/assets/main.css
@import "tailwindcss";

In v3 this was three lines: @tailwind base;, @tailwind components; and @tailwind utilities;. In v4 it is a regular CSS @import, and Tailwind takes over two jobs that used to need extra PostCSS plugins:

  • It bundles any further @import rules itself. In v3 that needed postcss-import.
  • It uses Lightning CSS underneath for vendor prefixes and nesting.

The new main.css no longer imports the base.css that create-vue ships, so you can delete that file. Run npm run dev and the utilities work in every component.

Add design tokens with @theme

Design tokens, the named values a project agrees on for colours, fonts and spacing, used to live in a JavaScript object. In v4 they are CSS variables inside an @theme block, in the same file:

src/assets/main.css
@import "tailwindcss";

@theme {
  --font-display: "Satoshi", sans-serif;
  --color-brand-500: oklch(0.62 0.17 250);
  --color-brand-700: oklch(0.45 0.15 250);
}

The oklch() numbers are lightness, chroma (how vivid) and hue. sans-serif is the fallback until you load the Satoshi web font, and it has no quotes on purpose: quoted, it would name a font called "sans-serif".

Each variable creates utilities. --color-brand-500 gives you bg-brand-500, text-brand-500, border-brand-500 and every other colour utility. --font-display gives you font-display. The announcement shows the same pattern for breakpoints (--breakpoint-3xl: 1920px) and easing curves.

Tailwind also writes the variables into the built CSS as ordinary custom properties on :root, so var(--color-brand-500) works in a component's <style> block or an inline style.

Use the token in a component

A pricing card with a heading, some text and a button, using the tokens from above:

src/components/PlanCard.vue
<script setup lang="ts">
defineProps<{
  name: string
  price: number
}>()
</script>

<template>
  <article class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
    <h2 class="font-display text-xl font-semibold text-slate-900">{{ name }}</h2>
    <p class="mt-2 text-slate-600">{{ price }} a month, cancel any time.</p>
    <button
      type="button"
      class="mt-4 rounded-lg bg-brand-500 px-4 py-2 text-white hover:bg-brand-700"
    >
      Choose {{ name }}
    </button>
  </article>
</template>

Import it into App.vue and render <PlanCard name="Pro" :price="12" />. If the button is blue, the @theme block is working: bg-brand-500 exists only because of it.

border-slate-200 is written out on purpose. In v4 the default border colour is currentColor, not gray-200 as it was in v3, so a bare border takes the text colour unless you give it one.

How Tailwind finds your classes

Tailwind only generates the classes you use, so it has to read your files. In v3 you listed the paths in a content array, and forgetting a folder meant missing styles. In v4 Tailwind finds template files on its own. The announcement says it skips anything in .gitignore, and binary files such as images and archives.

If some of your templates live somewhere Tailwind skips, such as a component library inside node_modules, point at it from CSS with @source:

src/assets/main.css
@import "tailwindcss";
@source "../../node_modules/@my-company/ui";

The path is relative to the CSS file. For a normal Vue project with components under src/, you will not need @source at all.

Upgrade a v3 project

For existing projects there is an upgrade tool:

npx @tailwindcss/upgrade

It needs Node 20 or newer, and it stops if git shows uncommitted changes, so commit first. The upgrade guide recommends running it on a new branch and reviewing the diff.

The tool updates your dependencies, moves your config into @theme, swaps the directives for the import, and renames the utilities whose scale shifted. Those renames are what to check in the diff:

  • shadow-sm is now shadow-xs, and the old shadow is shadow-sm. blur and drop-shadow shift the same way.
  • rounded-sm is now rounded-xs, and the old rounded is rounded-sm.
  • ring is now ring-3, because the default ring width went from 3px to 1px. The default ring colour also changed from blue-500 to currentColor, so add ring-blue-500 where you relied on it.
  • outline-none is now outline-hidden.

The tool deletes tailwind.config.js after moving its settings into CSS. If it cannot convert the file, it says so and keeps it, loaded from your CSS with an @config line. Keep it until you have moved those settings by hand.

The tool moves your PostCSS setup to the new @tailwindcss/postcss package, not to the Vite plugin. To switch, install and add @tailwindcss/vite as shown above, then remove Tailwind from postcss.config.js, or delete the file if nothing else is in it.

Check it stuck3 questions from the Tailwind CSS with Vue quiz.
Practice now
Was this helpful?

Keep reading