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

Arbitrary variants #8299

Merged
merged 18 commits into from May 8, 2022
Merged

Arbitrary variants #8299

merged 18 commits into from May 8, 2022

Conversation

RobinMalfait
Copy link
Contributor

With the new addVariant API, we have a beautiful way of creating new variants.

You can use it as:

addVariant('children', '& > *')

Now you can use the children: variant. The API uses a & as a reference for the candidate, which means that:

children:pl-4

Will result in:

.children\:pl-4 > * { .. }

Notice that the & was replaced by .children\:pl-4.

We can leverage this API to implement arbitrary variants, this means that you can write those &>* (Notice that we don't have spaces) inside a variant directly. An example of this can be:

<ul class="[&>*]:underline">
  <li>A</li>
  <li>B</li>
  <li>C</li>
</ul>

Which generates the following css:

.\[\&\>\*\]\:underline > * {
  text-decoration-line: underline;
}

Now all the children of the ul will have an underline. The selector itself is a bit crazy since it contains the candidate which is the selector itself, it is just escaped.

@@ -19,7 +19,7 @@ export function defaultExtractor(content) {
function* buildRegExps() {
yield regex.pattern([
// Variants
/((?=([^\s"'\\\[]+:))\2)?/,
/((?=([^\s"'\\]+:))\2)?/,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will require some work to make it exactly right

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol yep I was thinking about this. I'll throw this change against my new candidate refactor to see what breaks…

I had already tested support for arbitrary variant syntax (at least detection wise) in the form of [foo]:bar

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ngl I love this idea so much

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a regex tweak to fix the tests 👍👍

With the new `addVariant` API, we have a beautiful way of creating new
variants.

You can use it as:
```js
addVariant('children', '& > *')
```

Now you can use the `children:` variant. The API uses a `&` as a
reference for the candidate, which means that:
```html
children:pl-4
```

Will result in:
```css
.children\:pl-4 > * { .. }
```

Notice that the `&` was replaced by `.children\:pl-4`.

We can leverage this API to implement arbitrary variants, this means
that you can write those `&>*` (Notice that we don't have spaces) inside
a variant directly. An example of this can be:
```html
<ul class="[&>*]:underline">
  <li>A</li>
  <li>B</li>
  <li>C</li>
</ul>
```
Which generates the following css:
```css
.\[\&\>\*\]\:underline > * {
  text-decoration-line: underline;
}
```

Now all the children of the `ul` will have an `underline`. The selector
itself is a bit crazy since it contains the candidate which is the
selector itself, it is just escaped.
This still requires some work to the `defaultExtractor` to make sure it
all works with existing code.
@simonswiss
Copy link
Contributor

This is rad! 🤙

@onmax
Copy link

onmax commented May 8, 2022

Wow, just requested this feature about one month ago and now is coming here. Timing couldn't be better. I have a few ideas in my head to create some plugins with this.

#8157

Keep up the hard work 🔥 🔥. Amazing!

@adamwathan
Copy link
Member

Added a failing test for attribute selectors like:

class="[&:[data-open]]:underline"

I think this one is going to be kind of tricky — we need to reliable extract that candidate from the template but to do that we need to worry about bracket balancing. We'll need to support multiple pairs too so the implementation probably can't be as naive as I'd wish:

class="[&:[data-foo][data-bar]:has([data-baz])]:underline"

@adamwathan adamwathan changed the title WIP: Arbitrary variants Arbitrary variants May 8, 2022
@adamwathan adamwathan marked this pull request as ready for review May 8, 2022 16:24
@adamwathan adamwathan merged commit be51739 into master May 8, 2022
@adamwathan adamwathan deleted the arbitrary-variants branch May 8, 2022 16:24
@wenerme
Copy link

wenerme commented May 25, 2022

Hi, may I ask when will tailwindcss release next version contain this major feature ?

@jipika
Copy link

jipika commented Jun 9, 2022

Is it possible to specify a class name? Sometimes it is not possible to change all of them

@jipika
Copy link

jipika commented Jun 9, 2022

If you can specify the class name, in vue will not need to write:: v-deep and so on, you can directly modify the style of the UI library, which will greatly improve the efficiency of development

@calvo-jp
Copy link

calvo-jp commented Jun 9, 2022

woah! how cool 🚀

@ivanchenhz
Copy link

Cool, 👍
And seems we don't support class selector?!

[&_i]:text-pink-100 👌
[&_i.some_class]:text-pink-100 ...

@RobinMalfait
Copy link
Contributor Author

@ivanchenhz we do, but _ is used for spaces, so you essentially have this selector:

i .some class {}

You have to escape the _ if you want to keep it as an actual underscore. See: https://tailwindcss.com/docs/hover-focus-and-other-states#using-arbitrary-variants

@ivanchenhz
Copy link

@RobinMalfait thanks for confirming, and yes it works, 👍 😄
And I finally figure it out, the problem is we have prefix 'tw-'

  • So, when I targeting class like $_i.tw-font-medium it generate i.tw-tw-font-medium
  • Should we considering DON'T count prefix in arbitrary mode !

Screen Shot 2022-06-13 at 10 04 25 PM

Screen Shot 2022-06-13 at 10 04 12 PM

@ivanchenhz
Copy link

@RobinMalfait
Got a real case for this, we like to restyling the 'popover-body' which comes from some library
After add [&_.popover-body]:tw-pr-2, it auto prefix to generate tw-popover-body ( doesn't actually exist )
Have to manually add the class to make it work, ( which not feasible obviously 😂 )
Please considering don't count prefix in arbitrary mode

Screen Shot 2022-06-13 at 11 07 57 PM

@Emre-Zero
Copy link

Emre-Zero commented Sep 30, 2022

Nice work!

I suppose can shorten to ch.

(FYI for others), in tailwind.config.js:

const plugin = require("tailwindcss/plugin");
plugins: [
      plugin(function({ addVariant }) {
        addVariant('ch', '& > *')
      })
]

@clintfisher
Copy link

Having issues with Arbitrary variants not showing in Intellisense:
#9449

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.

None yet