Migrate from Tailwind CSS v3 to v4 including configuration migration (JS to CSS), utility renames, opacity changes, and color system updates. Use when upgrading existing projects to v4.
Migrates Tailwind CSS v3 projects to v4, including configuration conversion from JS to CSS, utility renames, and color system updates. Use when upgrading existing projects to v4.
/plugin marketplace add djankies/claude-configs/plugin install tailwind-4@claude-configsThis skill is limited to using the following tools:
references/breaking-changes.mdreferences/migration-checklist.mdMigrate existing Tailwind CSS v3 projects to v4's CSS-first configuration, updated utilities, and modern color system.
Tailwind provides an automated upgrade tool:
npx @tailwindcss/upgrade@next
Requirements:
What it handles:
What it doesn't handle:
v3 (tailwind.config.js):
module.exports = {
content: ['./src/**/*.{html,js}'],
theme: {
extend: {
colors: {
brand: '#3b82f6',
accent: '#a855f7',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
display: ['Satoshi', 'sans-serif'],
},
spacing: {
18: '4.5rem',
72: '18rem',
},
borderRadius: {
'4xl': '2rem',
},
},
},
plugins: [],
};
v4 (CSS @theme):
@import 'tailwindcss';
@theme {
--font-sans: 'Inter', sans-serif;
--font-display: 'Satoshi', sans-serif;
--color-brand: oklch(0.65 0.25 270);
--color-accent: oklch(0.65 0.25 320);
--spacing-18: 4.5rem;
--spacing-72: 18rem;
--radius-4xl: 2rem;
}
v3:
content: ['./src/**/*.{html,js,jsx,ts,tsx}']
v4:
Automatic detection. No configuration needed.
Manual control (if needed):
@import 'tailwindcss';
@source "../packages/ui";
@source not "./legacy";
v3:
@tailwind base;
@tailwind components;
@tailwind utilities;
v4:
@import 'tailwindcss';
v3:
<div class="bg-black bg-opacity-50"></div>
<div class="text-gray-900 text-opacity-75"></div>
<div class="border-blue-500 border-opacity-60"></div>
v4:
<div class="bg-black/50"></div>
<div class="text-gray-900/75"></div>
<div class="border-blue-500/60"></div>
Migration pattern:
bg-opacity-{value} → bg-{color}/{value}text-opacity-{value} → text-{color}/{value}border-opacity-{value} → border-{color}/{value}v3:
<div class="flex-shrink-0"></div>
<div class="flex-shrink"></div>
<div class="flex-grow-0"></div>
<div class="flex-grow"></div>
v4:
<div class="shrink-0"></div>
<div class="shrink"></div>
<div class="grow-0"></div>
<div class="grow"></div>
Migration pattern:
flex-shrink-* → shrink-*flex-grow-* → grow-*v3:
<div class="shadow-sm"></div>
v4:
<div class="shadow-xs"></div>
Migration:
shadow-sm → shadow-xsv3 default:
<input class="ring" />
Ring width: 3px
v4 default:
<input class="ring" />
Ring width: 1px
To keep v3 behavior:
<input class="ring-3" />
v3:
<div class="border"></div>
Border color: gray-200
v4:
<div class="border"></div>
Border color: currentColor
To keep v3 behavior:
<div class="border border-gray-200"></div>
v3 (RGB):
colors: {
brand: '#3b82f6',
}
v4 (OkLCh):
@theme {
--color-brand: oklch(0.65 0.25 270);
}
Use conversion tool: https://oklch.com/
v3:
module.exports = {
plugins: {
'tailwindcss': {},
'autoprefixer': {},
},
};
v4:
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};
No longer need autoprefixer or postcss-import.
v3:
import tailwindcss from 'tailwindcss';
import autoprefixer from 'autoprefixer';
export default defineConfig({
css: {
postcss: {
plugins: [tailwindcss(), autoprefixer()],
},
},
});
v4:
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [tailwindcss()],
});
v3:
Placeholder text: gray-400
v4:
Placeholder text: currentColor at 50% opacity
To keep v3 behavior:
@layer base {
::placeholder {
color: theme('colors.gray.400');
}
}
v3:
button {
cursor: pointer;
}
v4:
button {
cursor: default;
}
To restore v3 behavior:
@layer base {
button {
cursor: pointer;
}
}
v3 (plugin required):
plugins: [require('@tailwindcss/container-queries')]
v4 (built-in):
No plugin needed. Use @container and @{breakpoint}: syntax.
v3:
Not available
v4:
<div class="transform-3d rotate-x-45 rotate-y-30 translate-z-12"></div>
v3:
Not available
v4:
<div class="opacity-100 starting:opacity-0 transition-opacity"></div>
borderCheck:
@import "tailwindcss";@tailwindcss/postcss@tailwindcss/viteEnsure:
OkLCh uses different color space. Convert hex to oklch using: https://oklch.com/
Check: