7.7 KiB
name, description, allowed-tools
| name | description | allowed-tools |
|---|---|---|
| migrating-from-v3 | 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. | Read, Write, Edit, Grep, Glob, Bash |
Migrating from v3 to v4
Purpose
Migrate existing Tailwind CSS v3 projects to v4's CSS-first configuration, updated utilities, and modern color system.
Automated Migration Tool
Tailwind provides an automated upgrade tool:
npx @tailwindcss/upgrade@next
Requirements:
- Node.js 20 or higher
- Run in a new git branch
- Review all changes manually
- Test thoroughly
What it handles:
- Updates dependencies
- Migrates configuration to CSS
- Updates template files
- Converts utility class names
What it doesn't handle:
- Custom plugins (manual migration needed)
- Complex configuration logic
- Dynamic class generation
Configuration Migration
JavaScript Config → CSS Theme
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;
}
Content Detection
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";
Import Syntax Changes
v3:
@tailwind base;
@tailwind components;
@tailwind utilities;
v4:
@import 'tailwindcss';
Utility Class Renames
Opacity Modifiers
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}
Flex Utilities
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-*
Shadow Utilities
v3:
<div class="shadow-sm"></div>
v4:
<div class="shadow-xs"></div>
Migration:
shadow-sm→shadow-xs- All other shadow utilities remain the same
Ring Width
v3 default:
<input class="ring" />
Ring width: 3px
v4 default:
<input class="ring" />
Ring width: 1px
To keep v3 behavior:
<input class="ring-3" />
Color System Changes
Default Border and Ring Colors
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>
OkLCh Color Space
v3 (RGB):
colors: {
brand: '#3b82f6',
}
v4 (OkLCh):
@theme {
--color-brand: oklch(0.65 0.25 270);
}
Use conversion tool: https://oklch.com/
PostCSS Configuration
Plugin Changes
v3:
module.exports = {
plugins: {
'tailwindcss': {},
'autoprefixer': {},
},
};
v4:
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};
No longer need autoprefixer or postcss-import.
Vite Plugin
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()],
});
Preflight Changes
Placeholder Colors
v3:
Placeholder text: gray-400
v4:
Placeholder text: currentColor at 50% opacity
To keep v3 behavior:
@layer base {
::placeholder {
color: theme('colors.gray.400');
}
}
Button Cursor
v3:
button {
cursor: pointer;
}
v4:
button {
cursor: default;
}
To restore v3 behavior:
@layer base {
button {
cursor: pointer;
}
}
Feature Additions
Built-in Container Queries
v3 (plugin required):
plugins: [require('@tailwindcss/container-queries')]
v4 (built-in):
No plugin needed. Use @container and @{breakpoint}: syntax.
3D Transforms
v3:
Not available
v4:
<div class="transform-3d rotate-x-45 rotate-y-30 translate-z-12"></div>
Starting Variant for Animations
v3:
Not available
v4:
<div class="opacity-100 starting:opacity-0 transition-opacity"></div>
Breaking Changes Checklist
- Update dependencies to v4
- Migrate tailwind.config.js to @theme
- Replace @tailwind directives with @import
- Update PostCSS configuration
- Convert opacity utilities (bg-opacity → bg-{color}/{value})
- Rename flex utilities (flex-shrink → shrink)
- Update shadow-sm to shadow-xs
- Add explicit border colors if using bare
border - Update ring-3 if expecting 3px default
- Convert hex colors to oklch()
- Remove container-queries plugin (now built-in)
- Test placeholder colors
- Test button cursor behavior
- Update arbitrary value syntax (spaces → underscores)
Migration Strategy
Phase 1: Preparation
- Create new git branch
- Ensure all changes committed
- Run automated migration tool
- Review generated changes
Phase 2: Configuration
- Convert tailwind.config.js to CSS @theme
- Update PostCSS/Vite configuration
- Replace @tailwind directives
- Add @source if needed
Phase 3: Utilities
- Search and replace opacity modifiers
- Rename flex utilities
- Update shadow utilities
- Add explicit border colors
- Convert hex colors to oklch()
Phase 4: Testing
- Test all pages/components
- Verify responsive behavior
- Check dark mode
- Test interactive states
- Validate production build
Phase 5: Cleanup
- Remove unused dependencies
- Delete tailwind.config.js
- Update documentation
- Commit changes
Common Issues
Styles Not Applying
Check:
- CSS import:
@import "tailwindcss"; - PostCSS plugin:
@tailwindcss/postcss - Vite plugin:
@tailwindcss/vite - Template files not in .gitignore
Class Names Not Working
Ensure:
- Class names are complete strings
- Not using dynamic concatenation
- Using underscores for spaces in arbitrary values
Colors Look Different
OkLCh uses different color space. Convert hex to oklch using: https://oklch.com/
Build Errors
Check:
- Node.js version (20+)
- Dependencies updated
- PostCSS config using correct plugin
See Also
- references/breaking-changes.md - Complete breaking changes list
- references/migration-checklist.md - Step-by-step migration guide