Files
Julius Marminge 0c01f443b2 fix: read variant tokens from flattened class selectors (#662)
* fix: read variant tokens from flattened class selectors

Tailwind 4.3.3 stopped nesting variants under the utility class and emits
compound selectors instead:

  <= 4.3.2                           4.3.3
  .active\:x { &:active { ... } }    .active\:x:active { ... }

The native processor only read `:active`, `:focus`, `:disabled`, theme
`:where(...)`, `:dir()` and `[data-*]` tokens from nested rules. On the
flattened form the leading class token was accepted and the rest of the
selector ignored, so every variant compiled as an unconditional style:
`active:bg-red-500` was red at rest, `disabled:opacity-50` always dim,
`dark:` always on.

Read variant tokens from the components that follow the class token too,
sharing one reader with the nested path. A flattened compound the runtime
cannot observe (`disabled:` also emits `[aria-disabled="true"]`) is
dropped, matching what its empty nested rule compiled to before.

Regression test feeds both selector shapes straight to ProcessorBuilder,
so it does not depend on which Tailwind the repo pins. With
`@tailwindcss/node` at 4.3.3 the existing suite goes from 11 failures
(pressable, touchables, data-attributes, dir) to green.

* chore: bump tailwind dependencies to 4.3.3

Root catalog, @tailwindcss/node and @tailwindcss/oxide in the package, and
@tailwindcss/vite in the vite example. The repo now runs its own suite
against the flattened variant selectors that 4.3.3 emits.

* fix: handle flattened theme roots on web and skip unobservable compounds

Two follow-ups from review and CI on Tailwind 4.3.3.

Web: Tailwind now flattens `:root { &:where(.dark, .dark *) {} }` into a
sibling `:root:where(.dark, .dark *) {}` rule. The rule visitor only
rewrote nested theme variants into `.dark`, so the flattened form kept its
`:root` prefix and a scoped `.dark` class could not select it; the
`bg-background in dark theme` e2e test failed. Route a theme-layer `:root`
rule whose second token is `:where(.theme)` through the same rewrite.

Native: a selector mixing a supported variant with a token the runtime
cannot observe (`disabled:active:` emits `[aria-disabled="true"]:active`)
used to keep the branch gated on `:active` alone. Track unsupported tokens
in `readSelectorVariants` and skip the whole selector instead of applying
it under a weaker condition.
2026-09-04 07:58:05 +02:00
..
2026-07-02 09:08:41 +02:00