tailwindcss icon indicating copy to clipboard operation
tailwindcss copied to clipboard

Invalid CSS generated for class like `[&>&]:before:XXX`

Open moshest opened this issue 1 year ago • 3 comments

What version of Tailwind CSS are you using?

For example: v3.4.4

Reproduction URL

https://play.tailwindcss.com/nQleJ1grpC

image

Describe your issue

When using a class like [&>&]:before:content-[''] the generated CSS output contain invalid class with ::before::before instead of only one ::before:

+.\[\&\>\&\]\:before\:content-\[\'\'\]>.\[\&\>\&\]\:before\:content-\[\'\'\]::before::before {
-.\[\&\>\&\]\:before\:content-\[\'\'\]>.\[\&\>\&\]\:before\:content-\[\'\'\]::before {
  --tw-content: '';
  content: var(--tw-content);
}

The same apply for classes like [&+&]:before:XXX.

moshest avatar Jun 21 '24 21:06 moshest

Hey thanks, we can definitely fix this (and it's already fixed in the v4 engine)!

I am curious though what the hell you are trying to do in a real project where you are using two & in an arbitrary variant 😆 Can you show me a real example of what you're doing?

adamwathan avatar Jun 21 '24 22:06 adamwathan

Thanks!

I'm trying to style a tree-like shape where items can be one after another, or nested.

This specific style is very helpful to design the tree borders and handle the case of nesting and siblings without any code.

moshest avatar Jun 22 '24 01:06 moshest

Got it! In your particular case, rearranging the variants to the correct order solves the problem:

https://play.tailwindcss.com/7ZU3MP4OnX

In v3, variants are applied inside out, so the variant on the right is applied first so you want before to be the first variant 👍

https://tailwindcss.com/docs/hover-focus-and-other-states#ordering-stacked-modifiers

For legacy reasons we have some special logic in place to try and hoist pseudo elements like ::before and ::after to the end of the selector even when you order your variants differently, but it's best to place them first and not rely on that band-aid hoisting logic, because as this issue demonstrates it's clearly not perfect 😄

To make thing's slightly worse this is the one significant breaking change we're planning for v4 because it surprises basically everyone, so in v4 variants will be applied from left-to-right which I think is a lot more intuitive. We'll provide a codemod for this though so it'll be an easy upgrade 👍

adamwathan avatar Jun 22 '24 11:06 adamwathan

Just ran into (what I think is) the same issue with the class [&>p:first]:mt-0, which is generating the invalid selector .\[\&\>p\:first\]\:mt-0>p:first. I was able to make it work by changing it to [&>p:first-child]:mt-0.

ysulyma avatar Dec 23 '24 03:12 ysulyma

Hey!

Going to close this issue now that Tailwind CSS v4 is out. In v4 the correct CSS should be generated because the order of variants is different (and more expected). E.g.: https://play.tailwindcss.com/LMHx5rBgiL

I would recommend to try and upgrade to Tailwind CSS v4. You can find the upgrade guide here: https://tailwindcss.com/docs/upgrade-guide

We also have a CLI tool that can help with upgrading your project(s): https://tailwindcss.com/docs/upgrade-guide#using-the-upgrade-tool


@ysulyma The :first pseudo-class is not a valid pseudo-class, but as you noticed you have to use :first-child instead. In Tailwind CSS we have a first variant that uses first-child behind the scenes.

If you want, you can use stacked variants to generate the CSS you want.

[&>p]:first:mt-0 or *:[p]:first:mt-0

These would generate the following CSS:

:is(.\*\:\[p\]\:first\:mt-0 > *):is(p):first-child {
  margin-top: calc(var(--spacing) * 0);
}

:is(.\[\&\>p\]\:first\:mt-0 > p):first-child {
  margin-top: calc(var(--spacing) * 0);
}

Hope this helps!

RobinMalfait avatar Jan 29 '25 22:01 RobinMalfait