Skip to content

Canonicalization: convert variants with arbitrary values to equivalent variants - #20380

Merged
RobinMalfait merged 3 commits into
mainfrom
fix/issue-20365
Aug 3, 2026
Merged

Canonicalization: convert variants with arbitrary values to equivalent variants#20380
RobinMalfait merged 3 commits into
mainfrom
fix/issue-20365

Conversation

@RobinMalfait

@RobinMalfait RobinMalfait commented Aug 3, 2026

Copy link
Copy Markdown
Member

This PR improves the canonicalization for variants with arbitrary values that could be converted to static variants (based on the user @theme).

If a variant was used where we would use the 'old' theme(…) function, then we did convert this to the more modern version:

- max-[theme(screens.lg)]:flex
+ max-[--theme(--breakpoint-lg)]:flex

But in this case we can go a step further and convert to max-lg:flex instead. This is safe to do because the --breakpoint-lg can't change at runtime because @media queries don't work with CSS variables, which is why we inline it.

/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@media (width < 64rem) { /* Notice that this is inlined, and not using a CSS variable */
  .max-\[--theme\(--breakpoint-lg\)\]\:flex {
    display: flex;
  }
}

@media (width < 64rem) { /* ... and we do the same here */
  .max-lg\:flex {
    display: flex;
  }
}

We can extend this logic to arbitrary values in those variants as well. In fact, we already did for a min-[64rem]:flex or [@media(width>=theme(screens.lg))]:flex, these both translated to lg:flex.

- min-[64rem]:flex
+ lg:flex

- [@media(width>=theme(screens.lg))]:flex
+ lg:flex

That's because the lg, md, … are static variants, whereas the others are functional variants (lg-[…] doesn't exist for example).

With this PR, we will tackle functional variants, which now results as:

- max-[64rem]:flex
+ max-lg:flex

Fixes: #20365

Test plan

  1. Added new tests
  2. Updated an older test where the canonicalization gets improved
  3. Added a regression test for the setup mentioned in the linked issue

@RobinMalfait
RobinMalfait requested a review from a team as a code owner August 3, 2026 11:00
@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (2): Last reviewed commit: "update changelog" | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e11580e-b4a3-42bc-9a8d-f68de54e5343

📥 Commits

Reviewing files that changed from the base of the PR and between 74d0783 and 6b778e5.

📒 Files selected for processing (1)
  • CHANGELOG.md

Walkthrough

Variant canonicalization now uses root-font-size-specific caches. It normalizes media and container query dimensions and indexes known functional variants. Arbitrary variants preserve existing canonical forms and migrate to equivalent breakpoint or container variants when appropriate. The upgrade codemod reads the updated cache structure and accepts multiple equivalent matches. Tests cover rem and px conversions, custom theme values, unknown sizes, and existing named variants.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: converting arbitrary variant values to equivalent canonical variants.
Description check ✅ Passed The description explains arbitrary variant canonicalization, theme-based conversions, tests, and the linked issue.
Linked Issues check ✅ Passed The implementation addresses issue #20365 by canonicalizing max, container, media-query, and pixel-based variants with rem-aware handling.
Out of Scope Changes check ✅ Passed The implementation, tests, and changelog changes directly support the stated canonicalization objectives with no unrelated changes.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/tailwindcss/src/canonicalize-candidates.ts (1)

1550-1557: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Equivalent-variant selection is unspecified and duplicated across both call sites. Both sites resolve a signature to a list of equivalent variant names and then take foundVariants[0]. The list order comes from the iteration order of designSystem.variants.entries() and getCompletions(root) in createPreComputedVariantsCache. That order is an internal detail of the variant registry, so the canonical output is not pinned by any explicit rule.

  • packages/tailwindcss/src/canonicalize-candidates.ts#L1550-L1557: replace the foundVariants[0] choice with a shared helper that applies an explicit preference rule, for example the shortest name with a lexicographic tie-break.
  • packages/@tailwindcss-upgrade/src/codemods/template/migrate-arbitrary-variants.ts#L37-L48: remove the duplicated guard-and-select block and call the same shared helper.
packages/tailwindcss/src/canonicalize-candidates.test.ts (1)

964-1020: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the rem option explicit in both test.each option objects.

The first block relies on the omitted-default rem: 16 path, while the second block only overrides collapse and logicalToPhysical. Add rem: 16 to the first options object and rem: undefined (or the equivalent no-conversion default) to the second so each expectation declares its own conversion precondition.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f029e69d-9848-4e79-be97-140c6df18e69

📥 Commits

Reviewing files that changed from the base of the PR and between 4be6110 and 74d0783.

📒 Files selected for processing (3)
  • packages/@tailwindcss-upgrade/src/codemods/template/migrate-arbitrary-variants.ts
  • packages/tailwindcss/src/canonicalize-candidates.test.ts
  • packages/tailwindcss/src/canonicalize-candidates.ts

Comment thread packages/tailwindcss/src/canonicalize-candidates.ts
@RobinMalfait
RobinMalfait merged commit 6def820 into main Aug 3, 2026
10 checks passed
@RobinMalfait
RobinMalfait deleted the fix/issue-20365 branch August 3, 2026 11:11
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.

canonicalizeCandidates has media query gaps

1 participant