-
-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrong merge of classes with text-prefix #368
Comments
Hey @christophstockinger! 👋 tailwind-merge doesn't have access to the tailwind.config.js file and you need to configure it separately so it knows about the text-button class. Here is an example on how to configure tailwind-merge: https://github.com/dcastil/tailwind-merge/blob/v2.2.0/docs/recipes.md#adding-custom-scale-from-tailwind-config-to-tailwind-merge-config. And here is the documentation on how the tailwind-merge configuration works: https://github.com/dcastil/tailwind-merge/blob/v2.2.0/docs/configuration.md#usage-with-custom-tailwind-config. (For myself) Related: #322, #321, #315, #302, #276, #275, #274, #250, #207 |
Hi @dcastil , sorry, but I don't see how I can get both classes out at the end. Unfortunately, the documentation is not really helpful here. You explained an example with box-shadow because there is a special case. But a concrete example with initial situation, configuration and result would be more helpful. |
This is the setup code you need. import { extendTailwindMerge } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
// use the `extend` key in case you want to extend instead of override
override: {
classGroups: {
'font-size': ['text-button', …]
}
}
}) Then you use the Not sure what special case you mean with box-shadow. The procedure should be the same like for font-size classes. |
Hi, I have same issue. I have defined a lot of extra classes using My twMerge wrapper function: import cx from 'classnames'
import type classNames from 'classnames'
import { extendTailwindMerge } from 'tailwind-merge'
import { colors } from '../../tailwind-config/colors'
import { surface } from '../../tailwind-config/semantics/surface'
import { border } from '../../tailwind-config/semantics/border'
import { background } from '../../tailwind-config/semantics/background'
import { touchHeight } from '../../tailwind-config/semantics/touchHeight'
import { fontFamilyGroup } from '../../tailwind-config/fonts/fontFamily'
import { translucent } from '../../tailwind-config/semantics/translucent'
import { borderRadiusKeys } from '../../tailwind-config/semantics/borderRadius'
import { paddingKeys } from '../../tailwind-config/semantics/padding'
import { marginKeys } from '../../tailwind-config/semantics/margin'
import { fontSize } from '../../tailwind-config/semantics/fontSize'
import { textColor } from '../../tailwind-config/semantics/textColor'
const twMerge = extendTailwindMerge({
extend: {
theme: {
spacing: Object.keys(touchHeight).map((key) => key),
colors: [
'transparent',
'currentColor',
...Object.keys(colors).map((key) => key),
{
surface: Object.keys(surface).map((key) => key),
},
{
border: Object.keys(border).map((key) => key),
},
{
background: Object.keys(background).map((key) => key),
},
{
text: Object.keys(textColor).map((key) => key),
},
{
translucent: Object.keys(translucent).map((key) => key),
},
],
borderRadius: Object.keys(borderRadiusKeys).map((key) => key),
padding: Object.keys(paddingKeys).map((key) => key),
margin: Object.keys(marginKeys).map((key) => key),
},
classGroups: {
'font-size': Object.keys(fontSize).map((key) => key),
'font-family': Object.keys(fontFamilyGroup).map((key) => key),
},
},
})
export const cn = (...inputs: classNames.ArgumentArray) => {
console.log('Inputs:', inputs)
const result = twMerge(cx(inputs))
console.log('Outputs: ', result)
return result
} Inputs console log: Output console log: Note the Interesting tho that From what I can tell it seems to think that |
Please ignore this. It was a config issue. Changed classGroups: {
'font-size': Object.keys(fontSize).map((key) => key),
'font-family': Object.keys(fontFamilyGroup).map((key) => key),
}, to classGroups: {
'font-size': Object.keys(fontSize).map((key) => `text-${key}`),
'font-family': Object.keys(fontFamilyGroup).map((key) => `font-${key}`),
}, and it worked! :) |
@ViktorPontinen nice that you could figure it out! In the |
@dcastil We are having the same issue with our custom font-size and colors. Configuring the classGroups like @ViktorPontinen fixed it mostly. But currently we are still having overlapping classes when we use the line-height modifier on the font-size class
Is there a configuration option that could fix this? |
Hey @WesselKroos! 👋 The bottom three cases are intended and should be correct (at least in the default config). Here is an explanation.
|
Hi @dcastil 👋 Your workaround for the second case was what I was still looking for. That has been resolved now that I've removed the font-size from the conflictingClassGroups. Regarding the first and third cases, I was able to resolve those by splitting up a combined font-size/line-height via a regex: // Replaces 'text-12/100' with 'text-12 leading-100' to prevent 'leading-110' from keeping 'text-12/100' and conflicting
const splitFontSizeAndLineHeight = (className?: ClassNameValue) =>
typeof className === 'string'
? className.replace(
/text-([0-9]+)\/([0-9]+)/g,
(_groups, text, leading) => `text-${text} leading-${leading}`,
)
: className;
export const cn = (...classNames: ClassNameValue[]) =>
twMerge(
...classNames.map((className) => splitFontSizeAndLineHeight(className)),
); So all issues in our project have been resolved. Thanks once again! |
@WesselKroos nice workaround! Just keep in mind that the transformation is unsafe and that you could end up in a case where the Tailwind style won't get applied because the class is missing in CSS. More on that in https://tailwindcss.com/docs/content-configuration#dynamic-class-names. |
@dcastil Thanks for the extra tip. I think I should be able to workaround that by safelisting our font-sizes and line-heights. |
Hi @dcastil, I'm writing as my last resolt, as I tried many configurations with extend/override, classGroups, conflictingClassGroups, etc... TW custom font size config: {
theme: {
extend: {
fontSize: {
'dr': ['72px', {lineHeight: '72px', letterSpacing: '-0.01em', fontWeight: 400}]
}
}
}
} Following your comment this is my config extension: const customTwMerge = extendTailwindMerge({
override: {
classGroups: {
'font-size': ["text-dr"],
'leading': ["text-dr"],
'tracking': ["text-dr"],
'font-weight': ["text-dr"]
}
}
});
console.log(customTwMerge("text-5xl", "leading-5", "font-light", "tracking-tighter", "text-dr")); The result is Use case 2: tailwind-merge 2.2.1 |
Hey @sabvente! 👋 Here is the config you need with some explaining comments. const twMerge = extendTailwindMerge({
// We're using `extend` because we want to add a value and not override an entire group
extend: {
classGroups: {
// Adding the custom font-size class here
'font-size': ['text-dr'],
},
conflictingClassGroups: {
// Adding the info that font-size conflicts with font-weight and tracking.
// Keep in mind that this makes all font-size classes conflict with font-weight tracking.
// We don't need to define leading here because that is already in the default config.
'font-size': ['font-weight', 'tracking'],
},
},
}) For your use case 2: Not sure why you'd want to do this but you'd need to create a new group for text-dr which conflicts with the usual font-sizes but not the other way around. You can do that with this config where I call this extra group // In case you're using TypeScript: We need to tell tailwind-merge that we want to use a new class.
const twMerge = extendTailwindMerge<'font-size-2'>({
// We're using `extend` because we want to add a value and not override an entire group
extend: {
classGroups: {
// Adding the custom group with your font-size class here
'font-size-2': ['text-dr'],
},
conflictingClassGroups: {
// Adding the info that our font-size-2 group conflicts with font-size, leading, font-weight and tracking.
// Keep in mind that font-size won't conflict with font-size-2 as you want it.
// For that you'd need to add `'font-size': ['font-size-2']` here.
'font-size-2': ['font-size', 'leading', 'font-weight', 'tracking'],
},
},
}) |
In case you have more questions, please open a new issue. No need to send notifications to all the people in this thread. 😊 I'm closing this one as resolved. |
Hey @dcastil this might sound dumb but why isn't this the case? Shouldn't the full tailwind.config file be enough to automatically figure out all the conflicting classes and avoid having to configure twMerge as well? In fact, the Tailwind CSS IntelliSense VS code plugin probably does this already since it manages to warn you when you have conflicting classes in the same string and it automatically picks up custom configurations from the config file |
@JRebella tailwind runs at build-time, while tailwind-merge runs at runtime. So, including the full tailwind.config in tailwind-merge means that the final bundle size increases a lot. There is a request for tailwind to make it possible for third party tools to retrieve information about all final used classes (like a config which only contains the used configurations). You can get more info in this discussion: #413 (comment) |
Hey @JRebella! 👋 @WesselKroos already said it all. It is possible to create a Tailwind plugin that runs at build-time. But it's difficult to get the ergonomics right because the plugin would need to generate code which can easily create a frustrating experience. Especially during development with hot module replacements, etc. tailwind-merge is just the runtime part of it, but anyone can build on top of it and expand it to generate the config automatically. Maybe I'll do it some day, when I have some time and energy for it. |
Describe the bug
I have the following definition in my Tailwind-Config:
If I now define the classes
text-button
andtext-black
on a button, the classtext-button
is removed.However, this should not happen because the two classes have different instructions. The class
text-button
only takes care of the font-size and is a pardon totext-base
. The classtext-black
is responsible for the color.To Reproduce
Expected behavior
Both classes are rendered and the corresponding value is used for merging.
Environment
Additional context
./.
The text was updated successfully, but these errors were encountered: