Skip to content

fix(react-email): resolve theme variables used inside Tailwind utility variables - #3803

Open
hsusul wants to merge 1 commit into
resend:canaryfrom
hsusul:fix/tailwind-theme-vars-in-custom-properties
Open

hsusul wants to merge 1 commit into
resend:canaryfrom
hsusul:fix/tailwind-theme-vars-in-custom-properties

Conversation

@hsusul

@hsusul hsusul commented Oct 24, 2026

Copy link
Copy Markdown

Closes #3801.

Gradients, shadow/ring colors, blur-*, drop-shadow-* and translate-* with theme values inlined var(--color-…)/var(--spacing), which email clients drop because nothing defines them. Arbitrary values and direct utilities were fine. The broken ones go through Tailwind's --tw-* variables.

resolveAllCssVariables had two gaps:

  1. It never looked for var() inside custom property values, so --tw-gradient-from: var(--color-red-500) was never resolved against :root. css-tree parses custom property values as Raw, so they're parsed as values before walking.
  2. It cached each definition as a string at collection time, so a later use, like filter: var(--tw-blur,), got the unresolved text. Replacements now read the definition's current value.

A var() inside a custom property that has no matching definition keeps its fallback. Another class on the element may still define it at inline time. For example, shadow-red-500 sets --tw-shadow-color for shadow-md's --tw-shadow. Substituting the fallback early would break that.

Most of the diff in resolve-all-css-variables.ts is re-indentation from dropping the else. Use ?w=1 to see the real change.

Not addressed: shadow-black/20 still leaves a color-mix(in oklab, rgb(0,0,0,0.2) 100%, transparent) after resolution. That's a separate color-mix downleveling issue.

Tests

  • A resolver unit test for var() inside custom property definitions and the stale-definition case (--tw-blur).
  • A <Tailwind> render test covering a three-stop theme gradient, theme shadow-*/ring-* colors, blur-sm and translate-x-2, which asserts no var( in the output.
  • Both fail on canary and pass with the fix. No existing snapshot changed.
  • pnpm test in packages/react-email (316 passed), pnpm typecheck and pnpm lint all pass locally.

This doesn't conflict with #3795, which touches the same file: it applies cleanly on top, and the Tailwind tests pass with both.

@changeset-bot

changeset-bot Bot commented Oct 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bab4857

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
react-email Patch
@react-email/editor Patch
@react-email/ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

@hsusul is attempting to deploy a commit to the resend Team on Vercel.

A member of the Team first needs to authorize it.

This branch has not been deployed

No deployments
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.

Tailwind: gradients, shadow/ring colors, blur and translate inline unresolved var(--color-…) / var(--spacing)

1 participant