Skip to content

Don't collapse utilities into a utility with other theme variables - #20574

Merged
RobinMalfait merged 5 commits into
mainfrom
robin/don-t-collapse-utilities-into-other-theme-variables
Oct 14, 2026
Merged

RobinMalfait merged 5 commits into
mainfrom
robin/don-t-collapse-utilities-into-other-theme-variables

Conversation

@RobinMalfait

Copy link
Copy Markdown
Contributor

This PR fixes an issue where canonicalizeCandidates(…, { collapse: true }) replaces a group of utilities with a utility that uses a different theme variable. The two variables only have the same value by default.

Given this theme:

@theme {
  --spacing-card: 1rem;
  --spacing-other: 1rem;
}
Input Before After
mt-card mb-card my-4 my-card
w-card h-card size-4 size-card
mt-card mb-other my-4 mt-card mb-other
w-card h-other size-4 w-card h-other
mt-card mb-4 my-4 mt-card mb-4
p-card px-other p-card p-card px-other

The results on the left render differently once one of the variables changes, e.g. in .dark, in a media query, or in a class.

The cause

Signatures inline theme variables to their default value. This is correct for single candidates (e.g. text-[var(--color-red-500)] → text-red-500). But var(--spacing-card) and calc(var(--spacing) * 4) then both become 1rem, so the collapse step can't see which variable a utility uses.

The fix

A new cache compiles a utility the same way as its signature, and records the theme variables that are inlined in each declaration. The collapse step only uses this after the signature of a replacement already matches. Then each declaration of the replacement must use the same theme variables as the candidates it replaces.

A declaration without theme variables can still become one with theme variables. This is the same as for single candidates (mt-[16px] → mt-4), and it keeps existing results like:

  • [width:16px] [height:16px] → size-4
  • [font-size:14px] [line-height:1.625] → text-sm/relaxed
  • mt-[1px] mb-[1px] → my-px
  • text-sm leading-5 → text-sm/5

No existing test expectation changes.

Performance

The theme variables are only computed for a replacement whose signature already matches, and they are cached. With 10 class lists and the full default theme, the extra compiles take about 0.35ms of about 28ms on the first call (about 1%). Repeated calls do no extra work.

Test plan

  • Added a regression test for the cases in the table above
  • All existing tests in packages/tailwindcss pass

`mt-card mb-card` collapses into `my-4` when `--spacing-card` and
`--spacing` produce the same value by default. The result then uses
`--spacing` instead of `--spacing-card`, which renders differently once
one of the variables changes (e.g. in `.dark`).
No change in behavior. The next commit uses it to compute the theme
variables of a utility, with the same AST as its signature.
Signatures inline theme variables, so `mt-card mb-card` and `my-4` both
have `margin-top: 1rem; margin-bottom: 1rem` when `--spacing-card` is
`1rem`. The collapse step then picked `my-4`, and dropped the reference
to `--spacing-card`.

Now the collapse step also compares the theme variables that are inlined
in each declaration of the signature. A replacement has to use the same
theme variables as the candidates it replaces. A declaration without theme
variables can still become one with theme variables, so
`[width:16px] [height:16px]` still becomes `size-4`.

The theme variables are only computed for a replacement whose signature
already matches, so the extra work is small.
@RobinMalfait
RobinMalfait requested a review from a team as a code owner October 14, 2026 22:23
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3eef7110-4d29-4e64-88eb-5dccbe2edc74
📥 Commits

Reviewing files that changed from the base of the PR and between d4b5c63 and 79360b2.

📒 Files selected for processing: 3
  • CHANGELOG.md
  • packages/tailwindcss/src/canonicalize-candidates.test.ts
  • packages/tailwindcss/src/canonicalize-candidates.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

Candidate collapsing now checks theme-variable metadata in addition to compiled utility signatures. A shared compilation pipeline collects inlined theme variables for each declaration. Regression tests cover matching variables, differing variables, and mixtures of theme-backed and bare values. The changelog adds a fix entry describing the behavior.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 79360

The change stops candidate canonicalization from collapsing utilities that use different theme variables, and it adds regression tests for that behavior. No merge-blocking risk was identified.

Pre-merge checks: Passed 4
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: preventing utility collapse across different theme variables.
Description check Passed The description directly explains the bug, fix, affected examples, performance impact, and regression tests. It is fully related to the changeset.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@greptile-apps

greptile-apps Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Reviews (1) · Last reviewed commit: "Update changelog" · Reviewed by Greptile

@RobinMalfait
RobinMalfait enabled auto-merge (squash) October 14, 2026 22:30
@RobinMalfait
RobinMalfait disabled auto-merge October 14, 2026 22:37
@RobinMalfait
RobinMalfait merged commit d76d566 into main Oct 14, 2026
10 checks passed
@RobinMalfait
RobinMalfait deleted the robin/don-t-collapse-utilities-into-other-theme-variables branch October 14, 2026 22:37
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.

1 participant