fix(tailwindcss-react-aria-components): make not-* variants compose with native-overlapping states#9974
Conversation
…ith native-overlapping states Tailwind's `not-*` compound walker bails when a variant produces more than one style rule per path. The dual-selector (array) shape used for variants that overlap native CSS states (hover, focus, disabled, invalid, etc.) emitted two sibling rules, so `not-disabled:`, `not-invalid:`, `not-focus:`, `not-hover:`, and similar utilities silently generated no CSS. Collapse both branches into a single `:is()` selector. `:where()` keeps specificity at (0,1,0) so cascade behavior matches the previous output. Hover additionally needs `@media (hover: hover)` to prevent sticky styles on touch devices. Emitting it as a CSS-in-JS object (instead of a string starting with `@media`) causes Tailwind to report the variant's compounds as `StyleRules | AtRules`, which preserves `group-hover:` / `peer-hover:` composition while still giving `not-hover:` the "1 style rule + 1 at-rule per path" shape the walker requires. Test coverage extended with `not-*`, `group-not-*`, `peer-not-*`, `has-not-*`, `not-group-*`, `peer-hover:`, and `in-*` variants.
yihuiliao
left a comment
There was a problem hiding this comment.
Changes make sense. I cleaned up some dead code like removing the array branch in mapSelector and wrapSelector since getSelector no longer returns arrays or functions after this change. I ran the tailwind starter locally and spot checked it but would be good for other to verify as well. Once we get this merged, we can test through the RAC docs
…s not-* variants) (#172) * fix: restore input focus ring by patching tailwindcss-react-aria-components The plugin emits native state variants (invalid, focus, disabled, …) as two sibling rules — one for RAC elements ([data-rac][data-invalid]) and one for the native pseudo-class (:not([data-rac]):invalid). Tailwind's not-* compound walker bails out on multi-rule variants, so every not-invalid: utility silently emitted no CSS. The input field relies on focus:not-invalid:border-border-focus and focus:not-invalid:ring-border-focus-muted, so focused inputs lost their blue focus border and ring after the move to the official react-aria packages. Patch getSelector to collapse the two branches into a single :is() selector, keeping specificity at (0,1,0) via :where(), so not-* negation works again. Backports adobe/react-spectrum#9974. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style(input): apply oxfmt class ordering to styles.ts Pre-existing formatting drift flagged by oxfmt --check; reordering Tailwind classes in the source string is behavior-neutral (Tailwind decides precedence by its own internal sort, not class-attribute order). Keeps CI green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
snowystinger
left a comment
There was a problem hiding this comment.
How did you go about verifying the changes you've made here?
| .active\\:bg-red { | ||
| &:where([data-rac])[data-active] { | ||
| .in-hover\\:bg-red { | ||
| @media (hover: hover) { |
There was a problem hiding this comment.
does Tailwind's processor invert this? I don't think you can have @media inside a class selector. nevermind, i was thinking of old css
snowystinger
left a comment
There was a problem hiding this comment.
happy to get this in for testing, thanks
any validation you ran yourself would be much appreciated still
|
Patched it into my RAC-based library (dotUI) via pnpm patch (the exact :is() collapse here) and:
|
Problem
not-disabled:,not-invalid:,not-focus:,not-hover:and othernot-*utilities built on native-overlapping RAC variants silently emit no CSS.Tailwind's
not-*walker bails when a variant produces > 1 style rule per path (variants.ts#L470-L471), and the dual-selector (array) shape for these variants emits two siblings.Fix
Collapse both branches into a single
:is()—:where()keeps specificity at(0,1,0), so cascade is unchanged:For hover, emit as a CSS-in-JS object (not an
@media {...}string) so Tailwind reports compounds asStyleRules | AtRules, keepinggroup-hover:/peer-hover:composable.Known limitation
group-not-hover:/peer-not-hover:still don't compose — same architectural constraint that affects native Tailwind's owngroup-not-hover:.Test plan
not-*on every native-overlapping variant generates CSSgroup-hover:/peer-hover:/has-hover:unchanged semanticsgroup-not-disabled:,peer-not-disabled:,has-not-disabled:,not-group-hover:workrac-*) unchangedTesting instructions
we can test through the RAC docs once merged. test hover, disabled, press states