tailwindlabs / tailwindcss

A utility-first CSS framework for rapid UI development.
https://tailwindcss.com/
MIT License
80.82k stars 4.07k forks source link

JIT Prepend stackable variant before DEFAULT utilities CSS #3949

Closed navin-moorthy closed 2 years ago

navin-moorthy commented 3 years ago

What version of @tailwindcss/jit are you using?

v0.1.3

What version of Node.js are you using?

v15.5.1

What browser are you using?

Chrome

What operating system are you using?

macOS

Reproduction repository

https://github.com/navin-moorthy/tailwindcss-jit/pull/1

In our recent project Renderlesskit-react-tailwind, we make use of the Tailwind's variantOrder color: ["lib", "DEFAULT", "responsive"], to prepend our custom variant before the default utilities.

Generated output css in Renderlesskit-react-tailwind

lib\:text-red-500 {
  --tw-text-opacity: 1;
  color: rgba(239, 68, 68, var(--tw-text-opacity));
}

text-red-500 {
  --tw-text-opacity: 1;
  color: rgba(239, 68, 68, var(--tw-text-opacity));
}

But with the tailwind-jit, the variantOrder is not obeyed. Because of the ability to stack all variants after the DEFAULT utilities, our lib variant utilities always gets generated in the end.

Generated output css with tailwind-jit

text-red-500 {
  --tw-text-opacity: 1;
  color: rgba(239, 68, 68, var(--tw-text-opacity));
}

lib\:text-red-500 {
  --tw-text-opacity: 1;
  color: rgba(239, 68, 68, var(--tw-text-opacity));
}

But I have managed to find a hacky way to acheive this with tailwind-jit - PR

Generated output css with a Bigint hack in tailwind-jit

lib\:text-red-500 {
  --tw-text-opacity: 1;
  color: rgba(239, 68, 68, var(--tw-text-opacity));
}

text-red-500 {
  --tw-text-opacity: 1;
  color: rgba(239, 68, 68, var(--tw-text-opacity));
}

I would love to see this feature implemented if it's possible via some options.

adamwathan commented 3 years ago

Yeah this is something we need to figure out still for sure, will work on it šŸ‘šŸ»

iofjuupasli commented 2 years ago

I have config, with "d" for custom variant: variantOrder: ["d", "DEFAULT", ...defaultConfig.variantOrder] I think it doesn't work for reason of that issue

navin-moorthy commented 2 years ago

Here is the workaround to this issue that we are using,

https://gist.github.com/navin-moorthy/9bbfbb10129b0930375d34ae9d4e862c#gistcomment-3844152

navin-moorthy commented 2 years ago

Started using Tailwind Merge - https://github.com/dcastil/tailwind-merge as a workaround.

adamwathan commented 2 years ago

Hey folks! Unfortunately for now we don't have any plans to reintroduce support for variantOrder or to make it possible to generate custom variants earlier in the stylesheet than the default utilities.

Not opposed to coming up with a new solution for the problems this solves at some point in the future, but going to treat it as a feature request rather than a bug.

My personal recommendation is to write your code in a way that doesn't depend on having colliding classes added to the same element and needing to have one of them 'win' over the other one.

Generally this is through props on a component, so instead of something like this:

function MyComponent({ className }) {
  return (
    <div className={`rounded-md ... ${className}`}>
      ...
    </div>
  )
}

<MyComponent className="rounded-full" />

...do something like this:

function MyComponent({ radius = 'md' }) {
  let radiusClass = {
    md: 'rounded-md',
    full: 'rounded-full',
  }[radius]

  return (
    <div className={`${radiusClass} ... ${className}`}>
      ...
    </div>
  )
}

<MyComponent radius="full" />

If creating props for this sort of thing is prohibitive because of how many arbitrary overrides you find yourself needing to do, my gut is that the classes you are trying to override shouldn't be baked into the component at all.

Again not totally opposed to working on a solution for the core problem here eventually but right now that's what I would recommend, and is what we do in our own projects.

Another option is to use the ! modifier to make any overrides important:

<MyComponent className="!rounded-full" />

...but this feels a lot more likely to get messy and out of control to me. Hope that helps.