-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Improve support for custom variants in group-*
, peer-*
, has-*
, and not-*
variants
#14743
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit confusing but the results are really nice! I left some inline comments, mostly regarding the new compounds
property that we need to retain in the Variants map, but once this is more clear, let's just get this merged and hopefully not think about it again lol
7438dca
to
21a9523
Compare
6b3e870
to
a8e8360
Compare
TODOs:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, just a few things I noticed
We combine all style rule selectors into one when using the simple variant syntax `@variant (…);` At rules are still split into separate rules.
Right now there are only two possibilities: - `false` — this means a variant never compounds - `selector` — this means a variant only compounds if it does not produce at-rules
This doesn’t change what any of the rules support but makes it explicit
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
8d3b2bc
to
6ac6829
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of code here so might have missed it but I don't see tests for not-*
with arbitrary values other than not-[:checked]
— we should probably add tests for more complex arbitrary scenarios too.
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
|
|||
## [Unreleased] | |||
|
|||
### Added | |||
|
|||
- Added `not-*` versions of all builtin media query and supports variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Added `not-*` versions of all builtin media query and supports variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) | |
- Support `not-*` with all built-in media query and `supports-*` variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) |
### Added | ||
|
||
- Added `not-*` versions of all builtin media query and supports variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) | ||
- Improved support for custom variants with `group-*`, `peer-*`, `has-*`, and `not-*` ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to be clearer/more specific about what's actually possible now that wasn't before? I try to be really careful about using the format "Improve …" in changelog entries because it's not really clear what has actually changed
@@ -17,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
- Don't migrate important modifiers inside conditional statements in Vue and Alpine (e.g. `<div v-if="!border" />`) ([#14774](https://github.com/tailwindlabs/tailwindcss/pull/14774)) | |||
- Ensure third-party plugins with `exports` in their `package.json` are resolved correctly ([#14775](https://github.com/tailwindlabs/tailwindcss/pull/14775)) | |||
- Ensure underscores in the `url()` function are never unescaped ([#14776](https://github.com/tailwindlabs/tailwindcss/pull/14776)) | |||
- Fixed display of complex variants in Intellisense ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is meaningfully more specific but at least should use imperative mood for changelog entries to be consistent with other ones:
- Fixed display of complex variants in Intellisense ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) | |
- Ensure complex variants are displayed correctly in IntelliSense completions ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743)) |
Also capitalized "IntelliSense" consistent with how we do it elsewhere 👍
} | ||
|
||
compound( | ||
compoundWith( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If all compound variants need to specify their "with" do we actually need to change this name? I liked how before these methods were named as sort of factory functions for the variant kind, like static
, functional
, and compound
. I don't think we want to think of these as "compoundWith" variants do we, vs. still just "compound"?
} | ||
|
||
// Pseudo-elements are present so we can't compound | ||
if (sel.includes('::')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have to think about ::file-selector-button
as special here? I have tested a few things and don't think so, because in my testing :not(::file-selector-button)
doesn't work in any browser even though stuff like ::file-selector-button:is(:not(:active))
does work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No we don't — pseudo-elements don't work in :not(…), :is(…), :where(…), :has(…) and can't appear in the middle of a selector so .group
and .peer
are out too.
As for your 2nd example I think that's file:not-active:{utility}
yeah?
This PR does a number of of things that improve the ergonomics of using variants with
group
,peer
,has
, andnot
.The body-less
@variant
syntax now creates at most one style ruleFor example, in the following CSS:
The utility
test:flex
used to generate two separate rules:But it now generates only one rule:
This makes the generated CSS more concise and is simpler for compound variants to work with.
group-*
,peer-*
, andhas-*
are clearer about what they supportOne or more style rules MUST be present in the variant
A variant that is just a media query will not work with these variants:
The utilities
group-does-not-work:flex
,peer-does-not-work:flex
, andhas-does-not-work:flex
generate no CSS.However, if a style rule is present, it will work:
The utilities
group-works:flex
,peer-works:flex
, andhas-works:flex
generate the following CSS:Multiple style rules are okay
With nesting you can write a single rule like the following:
However you can also split this into two separate rules. It is functionally equivalent and works with
group-*
,peer-*
, andhas-*
:Which generates the following CSS for
group-test:flex
,peer-test:flex
, andhas-test:flex
:Nested style rules are NOT supported
We've so far ensured that nesting does not need to be flattened anywhere in core. Because of the nature of how
group-*
,peer-*
,has-*
, andnot-*
all work we'd have to implement a mechanism to flatten CSS ourselves. In the interest of keeping the core simpler we've decided to not support nested style rules in these variants.So for example, the following variant will not work with
group-*
,peer-*
,has-*
, ornot-*
:But if you manually flatten the nested style rules it will work:
Don't worry nested at-rules still work — for example:
produces the following CSS for
group-this-works-too:flex
,peer-this-works-too:flex
, andhas-this-works-too:flex
:Expands on variants supported by
not-*
The rules for
not-*
are very similar to the rules listed above but with some slight tweaks:@media
,@supports
, or@container
@media
at-rule must have one condition so a variant like@media screen, print
will not work withnot-*
The rules here are a bit complicated but hopefully you won't actually need to memorize these as most variants should end up being fairly simple in practice. We made sure to support these so things like
not-hover:flex
work as expected. These restrictions are in place to keep the core simple as implementing a full solution that handles arbitrarily nested at-rules and style-rules requires flattening nesting, interpreting CSS trees as logical expressions, and operating on those expressions. This is a non-trivial task that adds significant complexity to the codebase.Body-less variants no longer produce logically incorrect CSS
The
not-*
variant as its currently implemented can produce logically incorrect CSS depending on how the variant was written. For example, the following variant:Would generate the following CSS:
But with the first change we mentioned at the start of this description about body-less variants, this now generates the correct CSS:
not-*
now supports at-rule variants!Now things like
not-md:flex
,not-supports-grid:flex
,not-landscape
,not-motion-safe
, etc… all work as expected!This includes custom variants too! For example, given the following CSS:
The utilities
hdr:bg-red-900
andnot-hdr:bg-red-900
generate the following CSS:This works with
@supports
and@container
as well. For example, given the following CSS:The utilities
grid:flex
,not-grid:flex
,contained-sm:flex
, andnot-contained-sm:flex
generate the following CSS:If your conditional at-rule already has a
not
we'll remove it — this works with@media
,@supports
, and@container
.For example, given the following CSS:
The utility
not-flex-only:flex
generates the following CSS: