Getting Started
Upgrading your Tailwind CSS projects from v2 to v3.
Tailwind CSS v3.0 is a major update to the framework with a brand new internal engine and as such includes a small number of breaking changes.
We take stability very seriously and have worked hard to make any breaking changes as painless as possible. For most projects, upgrading to Tailwind CSS v3.0 should take less than 30 minutes.
To learn more about what’s new in Tailwind CSS v3.0, read the Tailwind CSS v3.0 announcement on our blog.
Update Tailwind, as well as PostCSS and autoprefixer, using npm:
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
Note that Tailwind CSS v3.0 requires PostCSS 8, and no longer supports PostCSS 7. If you can’t upgrade to PostCSS 8, we recommend using Tailwind CLI instead of installing Tailwind as a PostCSS plugin.
If you are using nesting in your custom CSS (in combination with a PostCSS nesting plugin), you should also configure the tailwindcss/nesting
plugin in your PostCSS configuration to ensure compatibility with Tailwind CSS v3.0.
All of our first-party plugins have been updated for compatibility with v3.0.
If you’re using any of our plugins, make sure to update them all to the latest version at the same time to avoid version constraint errors.
npm install -D tailwindcss@latest \
@tailwindcss/typography@latest \
@tailwindcss/forms@latest \
@tailwindcss/aspect-ratio@latest \
@tailwindcss/line-clamp@latest \
postcss@latest \
autoprefixer@latest
For Tailwind CSS v3.0, the CSS-based CDN build we’ve offered in the past has been replaced by the new Play CDN, which gives you the full power of the new engine right in the browser with no build step.
To try it out, throw this <script>
tag in your <head>
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Example</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<!-- -->
</body>
</html>
The Play CDN is designed for development purposes only — compiling your own static CSS build is a much better choice in production.
The new Just-in-Time engine we announced in March has replaced the classic engine in Tailwind CSS v3.0.
The new engine generates the styles you need for your project on-demand, and might necessitate some small changes to your project depending on how you have Tailwind configured.
If you were already opting in to mode: 'jit'
in Tailwind CSS v2.x, you can safely remove that from your configuration in v3.0:
module.exports = {
mode: 'jit',
// ...
}
Since Tailwind no longer uses PurgeCSS under the hood, we’ve renamed the purge
option to content
to better reflect what it’s for:
module.exports = {
purge: [
content: [
// Example content paths...
'./public/**/*.html',
'./src/**/*.{js,jsx,ts,tsx,vue}',
],
theme: {
// ...
}
// ...
}
If you weren’t already using the purge
option in your project, it’s crucial that you configure your template paths now or your compiled CSS will be empty.
Since we’re not using PurgeCSS under the hood anymore, some of the advanced purge options have changed. See the new content configuration documentation for more information on advanced options.
The dark mode feature is now enabled using the media
strategy by default, so you can remove this key entirely from your tailwind.config.js
file, unless you’re using the class
strategy.
module.exports = {
darkMode: 'media',
// ...
}
You can also safely remove this key if it’s currently set to false
:
module.exports = {
darkMode: false,
// ...
}
In Tailwind CSS v3.0, every variant is automatically available for every utility by default, so you can remove the variants
section from your tailwind.config.js
file:
module.exports = {
// ...
variants: {
extend: {
padding: ['hover'],
}
},
}
Since all variants are now enabled by default, you no longer need to explicity enable these for custom CSS using the @variants
or @responsive
directives.
Instead, add any custom CSS to appropriate “layer” using the @layer
directive:
@variants hover, focus {
@layer utilities {
.content-auto {
content-visibility: auto;
}
}
Any custom CSS added to one of Tailwind’s layers will automatically support variants.
See the documentation on adding custom styles using CSS and @layer for more information.
In Tailwind CSS v3.0, transform and filter utilities like scale-50
and brightness-75
will automatically take effect without needing to add the transform
, filter
, or backdrop-filter
classes:
<div class="transform scale-50 filter grayscale backdrop-filter backdrop-blur-sm">
<div class="scale-50 grayscale backdrop-blur-sm">
While there’s no harm in leaving them in your HTML, they can safely be removed — with one exception. If you’re relying on transform
to create a new stacking context, you may want to leave it, otherwise you may run into z-order issues. Alternatively, replace it with relative
or isolate
to force a new stacking context.
The new engine introduces a new syntax for changing the opacity of color utilities that we recommend migrating to from utilities like bg-opacity-{value}
:
<div class="bg-black bg-opacity-25">
<div class="bg-black/25">
The old approach still works in all cases except when using a border-opacity-*
utility with the default border
class — in v3 you’ll need to explicitly specify your border color:
<div class="border border-opacity-25">
<div class="border border-gray-200/25">
Every other situation behaves the same, so aside from that change your projects will work exactly as they did before. We do recommend using the new syntax going forward though, and plan to disable utilities like border-opacity-*
and bg-opacity-*
by default in v4, though you will still be able to enable them if needed.
This new syntax works for all color utilities, even utilities that didn’t have any way to change the opacity in the past like from-red-500/75
.
Tailwind CSS v3.0 now includes every color from the extended color palette by default, including previously disabled colors like cyan, rose, fuchsia, and lime, and all five variations of gray.
In v2.0, several of the default colors were actually aliases for the extended colors:
v2 Default | v2 Extended |
---|---|
green | emerald |
yellow | amber |
purple | violet |
In v3.0, these colors use their extended names by default, so what was previously bg-green-500
is now bg-emerald-500
, and bg-green-500
now refers to the green from the extended palette.
If you’re using these colors in your project, the simplest way to upgrade is to alias them back to their previous names in your tailwind.config.js
file:
const colors = require('tailwindcss/colors')
module.exports = {
theme: {
extend: {
colors: {
green: colors.emerald,
yellow: colors.amber,
purple: colors.violet,
}
},
},
// ...
}
If you are already using a custom color palette, this change doesn’t impact you at all.
As part of enabling all of the extended colors by default, we’ve given the different gray shades shorter single-word names to make them more practical to use and make it less awkward for them to co-exist at the same time.
v2 Default | v2 Extended | v3 Unified |
---|---|---|
N/A | blueGray | slate |
gray | coolGray | gray |
N/A | gray | zinc |
N/A | trueGray | neutral |
N/A | warmGray | stone |
If you were referencing any of the extended grays, you should update your references to the new names, for example:
const colors = require('tailwindcss/colors')
module.exports = {
theme: {
extend: {
colors: {
gray: colors.trueGray,
gray: colors.neutral,
}
},
},
// ...
}
If you weren’t referencing any of the grays from the extended color palette, this change doesn’t impact you at all.
Some class names in Tailwind CSS v3.0 have changed to avoid naming collisions, improve the developer experience, or make it possible to support new features.
Wherever possible we have preserved the old name as well so many of these changes are non-breaking, but you’re encouraged to update to the new class names.
Those damn browser developers added a real overflow: clip
property, so using overflow-clip
for text-overflow: clip
is a really bad idea now.
We’ve renamed overflow-clip
to text-clip
, and renamed overflow-ellipsis
to text-ellipsis
to avoid the naming collision:
<div class="overflow-clip overflow-ellipsis">
<div class="text-clip text-ellipsis">
This is extremely unlikely to affect anyone, as there are very few use-cases for text-clip
and it’s only really included for the sake of completion.
We’ve added grow-*
and shrink-*
as aliases for flex-grow-*
and flex-shrink-*
:
<div class="flex-grow-0 flex-shrink">
<div class="grow-0 shrink">
The old class names will always work but you’re encouraged to update to the new ones.
Since browsers are finally starting to respect border radius when rendering outlines, we’ve added separate utilities for the outline-style
, outline-color
, outline-width
and outline-offset
properties.
This means that outline-white
and outline-black
now only set the outline color, whereas in v2 they set the color, width, style, and offset.
If you are using outline-white
or outline-black
in your project, you can bring back the old styles by adding the following custom CSS to your project:
@layer utilities {
.outline-black {
outline: 2px dotted black;
outline-offset: 2px;
}
.outline-white {
outline: 2px dotted white;
outline-offset: 2px;
}
}
Alternatively, you can update any usage of them in your CSS with the following classes:
<div class="outline-black">
<div class="outline-black outline-2 outline-dotted outline-offset-2">
<div class="outline-white">
<div class="outline-white outline-2 outline-dotted outline-offset-2">
We’ve added box-decoration-clone
and box-decoration-slice
as aliases for decoration-clone
and decoration-slice
to avoid confusion with all of the new text-decoration
utilities that use the decoration-
namespace:
<div class="decoration-clone"></div>
<div class="box-decoration-clone"></div>
<div class="decoration-slice"></div>
<div class="box-decoration-slice"></div>
The old class names will always work but you’re encouraged to update to the new ones.
Tailwind CSS v3.0 necessitates a couple of other small breaking changes that are unlikely to affect many people, but have been captured here.
The dash (-
) character cannot be used as a custom separator in v3.0 because of a parsing ambiguity it introduces in the engine.
You’ll have to switch to another character like _
instead:
module.exports = {
// ...
separator: '-',
separator: '_',
}
Prior to Tailwind CSS v3.0, it was possible to define your class prefix as a function:
module.exports = {
// ...
prefix(selector) {
// ...
},
}
This isn’t possible in the new engine and we’ve had to remove support for this feature.
Instead, use a static prefix that is the same for every class Tailwind generates:
module.exports = {
// ...
prefix: 'tw-',
}
Super minor change since v3.0.0-alpha.2 where the file
modifier was introduced — if you were combining it with other modifiers like hover
or focus
, you’ll need to flip the modifier order:
<input class="file:hover:bg-blue-600 ...">
<input class="hover:file:bg-blue-600 ...">
Learn more in the ordering stacked modifiers documentation.
The fill-{color}
and stroke-{color}
utilities mirror your theme.colors
key by default now. This isn’t a breaking change if you haven’t customized your color palette, but if you have, the fill-current
and stroke-current
classes may not work if you don’t have current
included in your own custom color palette.
Add current
to your custom color palette to resolve this:
module.exports = {
// ...
theme: {
colors: {
current: 'currentColor',
// ...
}
}
}
The negative prefix in utilites like -mx-4
is a first class feature in Tailwind now, rather than something driven by your theme, so you can add -
in front of any utility that support negative values and it will just work.
The negative values have been removed from the default theme, so if you were referencing them with theme()
, you will see an error when trying to compile your CSS.
Use the calc()
function to update any affected code:
.my-class {
top: theme('top.-4')
top: calc(theme('top.4') * -1)
}
In Tailwind CSS v3.0, the @tailwind base
directive must be present for utilities like transforms, filters, and shadows to work as expected.
If you were previously disabling Tailwind’s base styles by not including this directive, you should add it back and disable preflight
in your corePlugins
configuration instead:
@tailwind base;
@tailwind components;
@tailwind utilities;
module.exports = {
// ...
corePlugins: {
preflight: false,
},
}
This will disable Tailwind’s global base styles without affecting utilities that rely on adding their own base styles to function correctly.
The @tailwind screens
layer has been renamed to @tailwind variants
:
/* ... */
@tailwind screens;
@tailwind variants;
I think you are more likely to be attacked by a shark while working at your desk than you are to be affected by this change.