fix(react-email): convert border radius and max width to px in pixelBasedPreset

Merged
SW
18h ago
+85-5

Overview

This PR serves as a bug fix candidate for #3845 - currently pixelBasedPreset is documented as the fix for Tailwind's rem units in email clients, but rounded-* and max-w-* still come out in rem.

Technical difficulties

pixelBasedPreset only overrides theme.extend.fontSize and theme.extend.spacing. Every other scale Tailwind defines in rem passes through unchanged:

ClassBeforeAfter
rounded, rounded-sm0.25rem4px
rounded-md0.375rem6px
rounded-lg0.5rem8px
max-w-md28rem448px
max-w-7xl80rem1280px

Considered and rejected:

  • Documenting it only (telling users to extend theme.borderRadius themselves). This works, but the preset's name and docs promise pixels, and each user has to rediscover the gap.
  • Post-processing rem to px for every declaration. That would also change values users set deliberately, and em and calc() cases are not a plain multiply by 16. A scale-by-scale preset keeps the change explicit and opt-out-able, since a user's own theme still overrides it.

Each value is what the rem resolves to at a 16px root, matching how the existing spacing and fontSize scales were done.

Changes

  • tailwind.tsx: pixelBasedPreset gains a borderRadius scale (DEFAULT, xs to 4xl) and a maxWidth scale (3xs to 7xl).
  • tailwind.spec.tsx: regression tests for the converted classes, and one that checks no class in either scale still emits rem.
  • A patch changeset for react-email.

Side effect worth a look: maxWidth is Tailwind's container scale, so w-md, min-w-md and the other container-sized widths also change from rem to px.

Not addressed: max-w-screen-* (breakpoints, 48rem) and tracking-* (em) still emit rem/em. Outlook on Windows ignores border-radius whatever the unit, so this does not give it rounded corners. I also noticed blur-sm rendering as filter:blur(var(--blur-sm)) with an unresolved variable; that looks like a separate bug.

Testing

  • With the fix removed, the 8 new tests fail; with it, they pass. The whole Tailwind suite passes (151 tests), and tsc --noEmit and biome check are clean in packages/react-email.
  • Not run: the other packages that import pixelBasedPreset (for example packages/ui), and real email clients.

Demo and evidence

A runnable before/after demo lives on a separate branch so it stays out of this PR:
aporter/2611-rem-from-pixelbasedpreset-demo.
Its README walks through it: cd packages/react-email && npx tsx demo/ab.tsx renders the same email with and without the new scales and prints the rem values found in each, all to local HTML for review. The branch also holds captured evidence (evidence-02.txt to evidence-07.txt: the published-package baseline, per-class output, the scan of Tailwind's rem scales, and the mutation check for the tests).


Summary by cubic

Converts the pixelBasedPreset's border radius and max width scales to pixels, so rounded-* and max-w-* classes no longer emit rem. Previously the preset only overrode fontSize and spacing, leaving these scales in rem values that don't render reliably in email clients.

Side effects

  • Because maxWidth is Tailwind's container scale, container-sized w-* and min-w-* classes also switch from rem to pixels.
  • max-w-screen-* and tracking-* still emit rem/em.
  • Adds regression tests, updates affected snapshots in react-email and ui, and a patch changeset.