This document is only about breaking changes between v2 and v3. For a full list of changes, see the v3.0.0 release.
tailwind-merge v3 drops support for Tailwind CSS v3 and in turn adds support for Tailwind CSS v4. That means you should upgrade to Tailwind CSS v4 and tailwind-merge v3 together. All breaking changes are related to the Tailwind CSS v4 support.
The highlights:
- No breaking changes to
twMerge
other than it expecting classes supported in Tailwind CSS v4. - The
theme
scales tailwind-merge supports were changed and now match the Tailwind CSS v4 theme variable namespace.
If you have feedback of any kind regarding this release, feel free to open an issue or discussion. I'm always happy to hear from you!
By exports:
- All
extendTailwindMerge
createTailwindMerge
validators
DefaultThemeGroupIds
tailwind-merge v3.0.0 is expected to be used together with Tailwind CSS v4. That means only features that work in Tailwind CSS v4 are supported. If you intend to stay on Tailwind CSS v3, don't upgrade to tailwind-merge v3.0.0 because there are some breaking changes in expected class syntax.
In Tailwind CSS v3 tailwind-merge was in a difficult position with Tailwind's theme scales. If tailwind-merge implemented support for all theme scales, the bundle size would become twice as large. If it didn't support any theme scales, users would have had a difficult time extending scales that are used in many class groups, like in the case of the spacing
scale. tailwind-merge went with an awkward middle ground where it only supported theme scales that were used in multiple class groups.
Tailwind CSS v4 reduced the number of theme scales to only 18 (called theme variable namespaces now) which makes it possible for tailwind-merge to support all of them.
That means if you add the CSS variable --inset-shadow-deep
to your Tailwind CSS theme, you can add it to the theme
object in tailwind-merge like in the following example:
import { extendTailwindMerge } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
extend: {
theme: {
'inset-shadow': ['deep'],
},
},
})
Here's how to proceed with upgrading each individual theme scale that got removed or renamed. Just keep in mind that theme scales should only define the custom part of a class (i.e. deep
for the class inset-shadow-deep
) whereas class groups should define the whole class (i.e. inset-shadow-deep
for the class inset-shadow-deep
). Sometimes you might find that values you configured manually before are now supported by Tailwind CSS v4 by default in which case you can remove them from your tailwind-merge config.
Theme scale in tailwind-merge v2 | What to use in tailwind-merge v3 instead |
---|---|
borderColor |
theme scale color |
borderRadius |
theme scale radius |
borderSpacing |
theme scale spacing or class groups border-spacing-* |
borderWidth |
class groups border-w-* |
brightness |
class groups brightness and backdrop-brightness |
colors |
theme scale color |
contrast |
class groups contrast and backdrop-contrast |
gap |
class groups gap-* |
gradientColorStopPositions |
class groups gradient-from-pos , gradient-via-pos and gradient-to-pos |
gradientColorStops |
class groups gradient-from , gradient-via and gradient-to |
grayscale |
class groups grayscale and backdrop-grayscale |
hueRotate |
class groups hue-rotate and backdrop-hue-rotate |
inset |
theme scale spacing or class groups inset-* |
invert |
class groups invert and backdrop-invert |
margin |
theme scale spacing or class groups m-* |
opacity |
class groups opacity and backdrop-opacity |
padding |
theme scale spacing or class groups p-* |
saturate |
class groups saturate and backdrop-saturate |
scale |
class groups scale-* |
sepia |
class groups sepia and backdrop-sepia |
skew |
class groups skew-* |
space |
theme scale spacing or class groups space-* |
translate |
theme scale spacing or class groups translate-* |
In case you were modifying class groups in tailwind-merge v2 because their theme scale was previously not implemented, it is highly likely that you can move those definitions to the theme
object in tailwind-merge v3. E.g. if you previously modified the font-family
class group to add a custom font class, you can now use theme.font
instead. Check out the theme documentation for more info.
Tailwind CSS v4 removed support for custom separators for modifiers in Tailwind CSS classes and now only the default separator :
is allowed. Therefore tailwind-merge also removed support for custom separators and doesn't use the separator
key in its config anymore. If you use TypeScript, you'll see a type error if you try to use the separator
key in your config.
Remove the separator
key from your tailwind-merge config.
import { extendTailwindMerge } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
- separator: '_',
…
})
import { createTailwindMerge } from 'tailwind-merge'
const twMerge = createTailwindMerge(() => ({
- separator: '_',
…
}))
extendTailwindMerge
and createTailwindMerge
: Prefix defined in config shouldn't include combining character anymore
In Tailwind CSS v4 the optional prefix syntax of classes changed from being in front of the base class like in hover:*:tw-class
to looking like the first modifier of a class like in tw:hover:*:class
.
In tailwind-merge v2 you had to specify the prefix including the final dash character -
that combined the prefix with the base class. Due to the new syntax this combining character changes to :
. To prevent having to change your config if the combining character changes in the future, tailwind-merge v3 expects you to specify the prefix without the combining character.
Remove the dash character from the prefix in your tailwind-merge config.
import { extendTailwindMerge } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
- prefix: 'tw-',
+ prefix: 'tw',
…
})
import { createTailwindMerge } from 'tailwind-merge'
const twMerge = createTailwindMerge(() => ({
- prefix: 'tw-',
+ prefix: 'tw',
…
}))
tailwind-merge v3 adds a new mandatory field orderSensitiveModifiers
to the config to specify which modifiers should be considered order-sensitive. Learn more about order-sensitive modifiers in the documentation.
Add the orderSensitiveModifiers
field to your tailwind-merge config.
import { createTailwindMerge } from 'tailwind-merge'
const twMerge = createTailwindMerge(() => ({
+ orderSensitiveModifiers: [],
…
}))
If you have any order-sensitive modifiers in Tailwind, add them to the new orderSensitiveModifiers
field in your tailwind-merge config.
import { createTailwindMerge } from 'tailwind-merge'
const twMerge = createTailwindMerge(() => ({
…
+ orderSensitiveModifiers: ['before', '*', …],
}))
The validator isLength
was used to check whether a class part is a number (3
, 1.5
), a fraction (3/4
), or one of the strings px
, full
or screen
. This was used for most length-based scales but the name was not really precise in explaining what it allows.
Due to how length-based scales were changed in Tailwind CSS v4, tailwind-merge v3 now uses isNumber
and isFraction
instead depending on what each scale supports and strings like px
, full
and screen
are instead specified manually in the scales themselves. This makes it more obvious what those validators do.
You can rebuild the previous validator yourself.
import { validators } from 'tailwind-merge'
function isLength(value: string) {
return (
validators.isNumber(value) ||
validators.isFraction(value) ||
value === 'full' ||
value === 'px' ||
value === 'screen'
)
}
Replace all uses of validators.isLength
with validators.isNumber
, validators.isFraction
and the strings full
, px
and screen
depending on which of those your scale supports.
import { validators } from 'tailwind-merge'
- [validators.isLength]
+ [validators.isNumber, validators.isFraction, 'full', 'px', 'screen']
Due to the default theme keys changing, the string union of DefaultThemeGroupIds
changed as well. Since this is a TypeScript type, errors in TypeScript will determine how to handle this change.