-
I've added a couple of useful utility classes to my tailwind project: .vstack {
display: flex;
flex-direction: column;
}
.vstack-1 {
display: flex;
flex-direction: column;
gap: 4px;
}
... for all `theme.gap` values, and the same with `hstack` and `flex-direction: row;` This works great, but I'm facing an issue when using it with twMerge('vstack-4 hidden') // 'vstack-4 hidden' Ideally I tried to configure it via Any help configuring tailwind merge here, in either configuration would be greatly appreciated. P.S.
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
Note Examples in this comment are using the tailwind-merge v1 API. Hey @bengry! 👋 Thanks for your patience! You need to tell tailwind-merge how conflicts with the First we want to use the default config and only add a bit more config to it, so we'll use import { extendTailwindMerge } from 'tailwind-merge'
// We'll use this function for merging instead of the one exported from the tailwind-merge package
const twMerge = extendTailwindMerge({ /* our config here */ }) Then we want to resolve conflicts between the classes like import { extendTailwindMerge, validators } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
classGroups: {
vstack: [{ vstack: ['', validators.isNumber] }],
},
}) Now we want to remove import { extendTailwindMerge, validators } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
classGroups: {
vstack: [{ vstack: ['', validators.isNumber] }],
},
conflictingClassGroups: {
display: ['vstack'],
},
}) We probably also want to remove preceding display classes when we add a vstack class, so we also configure the conflict into the other direction: import { extendTailwindMerge, validators } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
classGroups: {
vstack: [{ vstack: ['', validators.isNumber] }],
},
conflictingClassGroups: {
display: ['vstack'],
vstack: ['display'],
},
}) Additionally, we also want to remove preceding flex-direction and gap classes. So we make sure those are removed as well when a import { extendTailwindMerge, validators } from 'tailwind-merge'
const twMerge = extendTailwindMerge({
classGroups: {
vstack: [{ vstack: ['', validators.isNumber] }],
},
conflictingClassGroups: {
display: ['vstack'],
vstack: ['display', 'gap', 'gap-y', 'flex-direction'],
},
}) And that's it. Now you get this behavior: twMerge('vstack-3 hidden') === 'hidden'
twMerge('gap-2 flex-row vstack-3') === 'vstack-3' If you want to know how the configuration works, here is the documentation for it: https://github.com/dcastil/tailwind-merge/blob/v1.14.0/docs/configuration.md#usage-with-custom-tailwind-config. And here is an example on how to configure tailwind-merge: https://github.com/dcastil/tailwind-merge/blob/v1.14.0/docs/recipes.md#adding-custom-scale-from-tailwind-config-to-tailwind-merge-config. By the way, I find configuring helper classes like this in tailwind-merge quite complicated and annoying, especially if they define multiple CSS properties. So I use a different technique to create helpers like this where I don't need to configure anything in tailwind-merge: I define them as global variables which consist of the regular Tailwind CSS classes which tailwind-merge can work with by default. E.g. when I know that I only use 4 different const VSTACK_1 = 'flex flex-col gap-1'
const VSTACK_2 = 'flex flex-col gap-2'
const VSTACK_3 = 'flex flex-col gap-3'
const VSTACK_4 = 'flex flex-col gap-4' and then when I want to apply a vstack somewhere, I just use the variable: function MyComponent({ className }) {
return <div className={twMerge(VSTACK_2, /* more classes */, className)}>{/* code */}</div>
} When someone calls |
Beta Was this translation helpful? Give feedback.
-
This requires importing these constants everywhere, which kind of ruins the appeal of tailwind, in some way. I like the fact that I have everything on-hand without needing to import anything, and the JIC compiler does the rest to tree-shake the unused stuff and the linter to warn me of non-existent classes. This does make me think that perhaps declare function twExpand(...classes: ClassValue[]): string;
twExpand('vstack-1') === 'flex flex-col gap-1' Not perfect, since it does mean you have to use |
Beta Was this translation helpful? Give feedback.
-
is there any way like this? When I use a custom utility class (vstack-n in the example) and a utility class (hidden in the example) for a tw-merge function, I want to overwrite only the conflicting individual properties if they conflict with individual properties within the custom utility class and leave the remaining individual properties intact (in the example, I want to overwrite only the display properties and leave the flex-direction, gap) |
Beta Was this translation helpful? Give feedback.
Note
Examples in this comment are using the tailwind-merge v1 API.
Hey @bengry! 👋 Thanks for your patience!
You need to tell tailwind-merge how conflicts with the
vstack
(andhstack
) classes should be handled. Here a little tutorial:First we want to use the default config and only add a bit more config to it, so we'll use
extendTailwindMerge
like this:Then we want to resolve conflicts between the classes like
vstack
andvstack-4
. For this we create a new class group. tailwi…