Skip to content
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

background image and background color is merged making it impossible to apply both #488

Open
crtl opened this issue Nov 4, 2024 · 7 comments
Labels
context-v2 Related to tailwind-merge v2

Comments

@crtl
Copy link

crtl commented Nov 4, 2024

Describe the bug

When using custom gradients you may want to apply both a gradient as background-image and a background-color.
Currently tailwind-merge will remove "duplicate" properties based on their prefix even though they apply different styles.

To Reproduce

Having following custom gradient:

backgroundImage: {
  "my-gradient": "linear-gradient(0deg, var(--alpha-50, rgba(9, 9, 11, 0.50)) 0%, var(--alpha-50, rgba(9, 9, 11, 0.50)) 100%)"
}

Will generate a classname bg-my-gradient to apply the gradient.

// Im using cn helper from shadcn:
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

cn("bg-red bg-my-gradient"); // Returns bg-my-gradient, but should be bg-red bg-my-gradient

Environment

  • "tailwind-merge": "^2.5.4",
  • "clsx": "^2.1.1",

Additional context

As a workaround you can use media-query modifiers:

cn("sm:bg-red bg-my-gradient"); // Returns sm:bg-red bg-my-gradient
@github-actions github-actions bot added the context-v2 Related to tailwind-merge v2 label Nov 4, 2024
@dcastil
Copy link
Owner

dcastil commented Nov 14, 2024

Hey @crtl! 👋 Thanks for your patience!

tailwind-merge doesn't have access to the tailwind.config.js file and you need to configure it separately so it knows about the bg-my-gradient class.

Here is an example on how to configure tailwind-merge: https://github.com/dcastil/tailwind-merge/blob/v2.5.4/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.5.4/docs/configuration.md#usage-with-custom-tailwind-config.


(For myself)

Related: #489, #469, #447, #368, #322, #321, #315, #302, #276, #275, #274, #250, #207

@LikeDreamwalker
Copy link

To make a note:
This issue basically because tailwind-merge can't visit tailwind config directly, so even if we have declare the new variable in the tailwind config, tailwind-merge can't understand what all these custom variables are. And by some reasons in the tailwind-merge these custom variables and original tailwind variables will always try to overwrite each other.
And the solution is above, to use the extendTailwindMerge to create the new extended merge functions.

For the shadcn/ui scenario, you can try this:

import { clsx, type ClassValue } from "clsx";
import { extendTailwindMerge } from "tailwind-merge";

const customTwMerge = extendTailwindMerge({
  extend: {
    classGroups: {
      // Add custom merging rules here
      "font-size": [
        "text-h1",
        "text-h2",
        "text-h3",
        // ... and so on
      ],
      "bg-color": [
        "bg-background",
        "bg-foreground",
        "bg-card",
      ],
      "text-color": [
        "text-background",
        "text-foreground",
        "text-card-foreground",
      ],
      "border-color": [
        "border-background",
        "border-foreground",
        "border-card",
      ],
      z: ["z-app-bar", "z-popup", "z-menu", "z-tooltip", "z-modal"],
    },
  },
});

export function cn(...inputs: ClassValue[]) {
  return customTwMerge(clsx(inputs));
}

It is a solution for me, and I am not sure if this will affect shadcn/ui because Copilot also send some shadcn/ui variable into it.

@dcastil
Copy link
Owner

dcastil commented Nov 18, 2024

And by some reasons in the tailwind-merge these custom variables and original tailwind variables will always try to overwrite each other.

tailwind-merge by default treats classes that could be a color class as a color class, e.g. bg-whatever. I did this because colors are changed very often in the config and this allows you to set up custom colors without the need to configure that in tailwind-merge.

The downside of course is that all unknown classes starting with bg- will be interpreted as a color class and therefore removed if another background-color class comes after it.

@LikeDreamwalker
Copy link

And by some reasons in the tailwind-merge these custom variables and original tailwind variables will always try to overwrite each other.

tailwind-merge by default treats classes that could be a color class as a color class, e.g. bg-whatever. I did this because colors are changed very often in the config and this allows you to set up custom colors without the need to configure that in tailwind-merge.

The downside of course is that all unknown classes starting with bg- will be interpreted as a color class and therefore removed if another background-color class comes after it.

I understand and that is just a note. I think maybe it will be a better practice to build the custom tailwind variables first, and then use it to generate the tailwind config and extended tailwind-merge function. Sadly that's not the shadcn/ui's style ❤

@GuiSelair
Copy link

This happened to me as well, but with the text-... class. I have custom classes for text-button-filled-label and text-button-md. One changes the button text color, and the other changes the font size, respectively. It merges the two and keeps only the last one. I can't use both together with tailwind-merge :(

@dcastil
Copy link
Owner

dcastil commented Dec 3, 2024

@GuiSelair you can, you just need to configure tailwind-merge accordingly:

import { extendTailwindMerge } from 'tailwind-merge'

export const twMerge = extendTailwindMerge({
    extend: {
        classGroups: {
            'font-size': ['text-button-md']
        }
    }
})

You don't need to configure text-button-filled-label because tailwind-merge defaults to all unknown classes beginning with text- to be interpreted as a text color class.

@GuiSelair
Copy link

@GuiSelair you can, you just need to configure tailwind-merge accordingly:

import { extendTailwindMerge } from 'tailwind-merge'

export const twMerge = extendTailwindMerge({
    extend: {
        classGroups: {
            'font-size': ['text-button-md']
        }
    }
})

You don't need to configure text-button-filled-label because tailwind-merge defaults to all unknown classes beginning with text- to be interpreted as a text color class.

It's works! Thanks you! 🥇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
context-v2 Related to tailwind-merge v2
Projects
None yet
Development

No branches or pull requests

4 participants