Skip to content

composite class does not merge with individual class #553

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

Open
unional opened this issue Mar 24, 2025 · 5 comments
Open

composite class does not merge with individual class #553

unional opened this issue Mar 24, 2025 · 5 comments
Labels
context-v3 Related to tailwind-merge v3

Comments

@unional
Copy link

unional commented Mar 24, 2025

Describe the bug

Hi @dcastil, this is sort of both a bug and a feature.

tailwind-merge current behavior for merging composite class with their individual class like this:

const a = twMerge('pl-1 p-0') // 'p-0'
const b = twMerge('p-0 pl-1') // 'p-0 pl-1'

This works fine locally, I believe, even with this:

const b = twMerge('p-0 pl-1') // 'p-0 pl-1'
const c = twMerge('p-0') // 'p-0'

because tailwind will place the .p-0 class before .pl-1 class:

.p-0 { ... }

.pl-1 { ... }

However, it will not work when a Tailwind app consuming a Tailwind lib:

// lib
export const A = ({ className }) => <div className={twMerge('p-0', className)}/>

/* got className='p-0 pl-1' */
export const B = ({ className }) => <A className='pl-1' />

// app
import { A, B } from 'lib'

export const C = () => (
  <div className='p-0'>
    <A />
    <B />
  </div>
)

Since p-0 appears in app, the resulting CSS:

/* from lib */
.p-0 { ... }
.pl-1 { ... }

/* from app */
.p-0 { ... }

This cause B to rendered with p-0 instead of pl-1.

PostCSS plugin postcss-discard-duplicates could not help here because it kept the last duplicate:

/* from lib */
/* .p-0 { ... } -- removed by postcss-discard-duplicates */
.pl-1 { ... }

/* from app */
.p-0 { ... }

One solution I can think of is transform p0 pl-1 to pr-0 pt-0 pb-0 pl-1.
But then tailwind couldn't generate the right classes.

@github-actions github-actions bot added the context-v3 Related to tailwind-merge v3 label Mar 24, 2025
@unional
Copy link
Author

unional commented Mar 24, 2025

ref: cssnano/cssnano#1583

@dcastil
Copy link
Owner

dcastil commented Mar 31, 2025

Hey! Yeah Tailwind CSS and tailwind-merge both rely heavily on the order of the CSS, so merging two Tailwind CSS stylesheets causes issues like this.

When using an independent lib which has its own Tailwind config in a project with its own Tailwind config, the typical solution I'm aware of is to add a prefix to one of the two Tailwind configs. Then you can still merge classes between the two, see #537.

@unional
Copy link
Author

unional commented Apr 1, 2025

Thanks for confirming that.

It also means that when working on a monorepo containing multiple packages of components using the same prefix, I have to use the tailwind config content (v3) or source (v4) to scan the source code of the depending packages.

One drawback is that it breaks the encapsulation on dependencies, i.e. we need to also update and include the transient dependencies.

v3 can get around that by importing the tailwind.config.js and combine the content (still need some custom transform),
but v4 doesn't have a way to do that because the config is css.

@dcastil
Copy link
Owner

dcastil commented Apr 1, 2025

You can still use a JS config in Tailwind CSS v4 → https://tailwindcss.com/docs/functions-and-directives#config-directive

@unional
Copy link
Author

unional commented Apr 2, 2025

Yeah, but that's a temporary solution. Tailwind team said it will be removed in the future.

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

No branches or pull requests

2 participants