Skip to content

Conversation

@aggreggator
Copy link
Contributor

Add variant for children.

Examples:
children:bg-red-100
hover:children:bg-red-500

@aggreggator aggreggator changed the title Add children variant Add children variant Nov 14, 2021
@Semvrij
Copy link

Semvrij commented Dec 7, 2021

Is there any news about this pull request?

@reinink
Copy link
Member

reinink commented Mar 4, 2022

Hey @aggreggator! So we really love this feature idea, and we'd really love to see this as part of Tailwind CSS some day, but there are some issues with this PR that are preventing us from merging it in. Consider this example:

<ul class="children:text-blue-500">
  <li>React</li>
  <li>Vue</li>
  <li class="text-red-500">Angular</li>
  <li>Svelte</li>
</ul>

In this example, I think the expected behavior would be that the text for each item would be blue-500, except for Angular, which would be red-500. Unfortunately, that isn't the case — they all remain blue-500:

image

That's because the children:text-blue-500 ends up being define after text-red-500 in the stylesheet, since Tailwind places modifiers after the base utilities:

.text-red-500 {
  color: rgb(239 68 68);
}

.children\:text-blue-500 > * {
  color: rgb(59 130 246);
}

However, to make this work you'd need the children modifiers to come before the utilities:

.children\:text-blue-500 > * {
  color: rgb(59 130 246);
}

.text-red-500 {
  color: rgb(239 68 68);
}

Then you'd get this result:

image

Now generally you actually do want modifiers ordered after the base utilities, since you use them to override the default styles. For example, if sm:text-red-500 wasn't ordered after the base utilities, you couldn't do something like this:

<div class="text-blue-500 sm:text-red-500">
  <!-- should be red -->
</div>

So, to properly support this in Tailwind we'd have to figure out a way to conditionally order certain modifiers before the utilities — which is a much more complicated problem to solve.

Again, this is something we'd love to solve some day in Tailwind, and we've already been having discussions about this as a team. However, given this ordering issue, we just don't feel comfortable merging this particular PR in, as much as we love the concept in general.

Some good news — if this is a feature you'd really like to have in your Tailwind project, and you're okay with the above mentioned limitations, you can easily add this behavior to your project via a plugin. Here's how:

module.exports = {
  content: [
    // ...
  ],
  theme: {
    extend: {
      // ...
    },
  },
  plugins: [
    function ({ addVariant }) {
      addVariant('children', '& > *')
    }
  ],
}

And, if you do run into the ordering issue, you can always cheat by using the important modifier 😅

<ul class="children:text-blue-500">
  <li>React</li>
  <li>Vue</li>
  <li class="!text-red-500">Angular</li>
  <li>Svelte</li>
</ul>

Even though it doesn't make sense to add this feature to Tailwind right now, I suspect this is something we're going to revisit in the future. Thanks either way for this contribution 🙏

@reinink reinink closed this Mar 4, 2022
@aggreggator
Copy link
Contributor Author

Hey @reinink !

i didn't expect to get such a detailed feedback and i agree with all of your objections to not merge it to tailwindcss.

Your first example shows clearly that the specificity of the children selector is higher than the individual class on the child.

I've rechecked this once again and my previous statement is just wrong.
The specificity is the same for both selectors and only the order in the generated CSS is crucial as you already mentioned.

It was clear to me, that you can only escape from this in using the important modifier on the individual child element.
But this would mostly not be clear for the ordinary tailwindcss user.

So, to properly support this in Tailwind we'd have to figure out a way to conditionally order certain modifiers before the utilities — which is a much more complicated problem to solve.

That's not trivial at all!
But your whole team already developed so many brilliant and pragmatic ideas.
Hope you will find also a way to solve this problem.
I'm clueless how to approach this!

Thank you all for the hard work! :-)

@aggreggator
Copy link
Contributor Author

I've just came up with an idea using the @layer directive.
But the browsers just started to support it, so there is nothing to rush.

I've prepared a codepen with your example, because tailwindcss (and https://play.tailwindcss.com/) already uses @layer in its own manner.

https://codepen.io/aggreggator/pen/Bamgxxz

@innocenzi
Copy link
Contributor

What if the :where pseudo-class was used for this? That would allow to remove the specificity. What could be the drawbacks of this approach?

Example with the CSS appended: https://play.tailwindcss.com/FlvyafjuIc
With the actual variant: https://play.tailwindcss.com/m7DmLnfZyU?file=config

.text-red-500 {
  color: rgb(239 68 68);
}

:where(.children\:text-blue-500 > *) {
  color: rgb(59 130 246);
}

@reinink
Copy link
Member

reinink commented Sep 27, 2022

@innocenzi yup that's a great idea too — the only issue is that the reset styles will then win out, as they will have higher specificity than the where() styles. Here's a Play that demonstrates this:

https://play.tailwindcss.com/QavZjsMiD4

One way to potentially solve that is to wrap all the styles in Preflight in where() — we just need to make sure that those styles will win out over the default user-agent styles (I think they will). Further, it's still early for a change like this to such a core part of Tailwind CSS, as where() browser support is still a little light.

@innocenzi
Copy link
Contributor

innocenzi commented Sep 27, 2022

Ah, that's a good point! Thanks for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants