Skip to content

fix(react-email): tighten error when <head> is missing inside <Tailwind>#3471

Open
mvanhorn wants to merge 2 commits intoresend:canaryfrom
mvanhorn:fix/3026-head-outside-tailwind
Open

fix(react-email): tighten error when <head> is missing inside <Tailwind>#3471
mvanhorn wants to merge 2 commits intoresend:canaryfrom
mvanhorn:fix/3026-head-outside-tailwind

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

@mvanhorn mvanhorn commented May 5, 2026

Summary

Restructure the missing-<head> error so the actionable instruction is the first line and the offending class list is on its own line. The prior message buried the directive inside three paragraphs of prose.

Why this matters

In #3026, @GeekCornerGH reported that adding dark:* classes inside <Tailwind> crashes the dev server. The repro template (also confirmed by @opswiz) places <Head /> outside <Tailwind>, which is what triggers the throw on tailwind.tsx:159-172. The error explained the cause, but with the directive buried mid-paragraph many users only saw the surrounding ELIFECYCLE Command failed with exit code 1.

@claygeo posted a thorough investigation pinpointing the throw site - credit for the diagnosis goes to them.

The new message reads:

Tailwind: <head> not found inside <Tailwind>.
Move <Head /> inside <Tailwind>, or remove these classes that require a <head>: dark:bg-white dark:text-gray-100.

If you do already have a <head> element at some depth, please file a bug at https://github.com/resend/react-email/issues/new?...

Changes

  • packages/react-email/src/components/tailwind/tailwind.tsx - tighten the throw at the missing-<head> site
  • packages/react-email/src/components/tailwind/tailwind.spec.tsx - new regression test covering <Head /> outside <Tailwind> with dark:* classes; the two existing snapshot-based throw assertions are converted to direct .toThrow() checks against the new message text
  • packages/react-email/src/components/tailwind/__snapshots__/tailwind.spec.tsx.snap - removed (the file's two entries were consumed by the spec changes above; no remaining snapshot calls in this spec)
  • .changeset/clear-tailwind-head-error.md - patch changeset for react-email

Testing

pnpm test passes (10/10 tasks, 35/35 tailwind tests). pnpm lint passes (one pre-existing CSS warning unrelated to this change).

Open question

Issue #3026 also asks for the dev server not to exit on render errors. That fix lands at the render call site in the preview app (the previously-cited render-email-by-path.tsx no longer exists on canary, so identifying the current site is part of the work). Happy to follow up in a separate PR - which call site do you want me to wrap, @gabrielmfern? Or would you prefer this PR stay scoped to just the error message?

Fixes #3026


Summary by cubic

Tightened the Tailwind missing <head> error in react-email so the fix is clear and immediate when <Head /> is outside <Tailwind>. Addresses the crash scenario reported in #3026 with dark:* classes.

  • Bug Fixes
    • Error now begins with the instruction and lists offending classes on a separate line.
    • Added a regression test for <Head /> outside <Tailwind> with dark:* classes; replaced snapshots with direct .toThrow() checks and removed the snapshot file.
    • Added a patch changeset for react-email and backticked <Head>/<Tailwind> in it to fix changelog rendering.

Written for commit 9996e62. Summary will update on new commits.

Restructure the missing-<head> error so the actionable instruction is
the first line and the offending class list is on its own line. The
prior message buried the directive inside three paragraphs of prose,
which made it easy for users to miss the real cause (e.g. when <Head />
is placed outside <Tailwind>, as in resend#3026 with dark:* classes).

Add a regression test for the failing topology (<Head /> OUTSIDE
<Tailwind>, with a Body containing dark:* classes) and convert the two
existing throw assertions from snapshot matching to direct .toThrow()
checks against the new message text.

Closes resend#3026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 5, 2026

🦋 Changeset detected

Latest commit: 9996e62

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
Copy link
Copy Markdown
Contributor

vercel Bot commented May 5, 2026

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

A member of the Team first needs to authorize it.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 5, 2026

Open in StackBlitz

npm i https://pkg.pr.new/react-email@3471

commit: 9996e62

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 4 files

Confidence score: 5/5

  • This PR looks low risk to merge: the only flagged item is a low-severity documentation/release-note formatting issue (3/10) rather than application runtime behavior.
  • The most severe issue is in .changeset/clear-tailwind-head-error.md, where raw <Head> / <Tailwind> may be parsed as HTML and cause generated changelog text to render incorrectly or be hidden.
  • Pay close attention to .changeset/clear-tailwind-head-error.md - escape or code-format the angle-bracket terms so release notes display as intended.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".changeset/clear-tailwind-head-error.md">

<violation number="1" location=".changeset/clear-tailwind-head-error.md:5">
P3: Raw `<Head>` / `<Tailwind>` in the changeset summary can be interpreted as HTML in generated changelogs, so the release note may render incorrectly or hide the text.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread .changeset/clear-tailwind-head-error.md Outdated
Raw <Head>/<Tailwind> were being interpreted as HTML in the generated
changelog. Backticks render them as inline code instead.

Spotted by cubic-dev-ai review on resend#3471.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Auto-approved: Only updates an error message string and corresponding tests; no logic, infrastructure, or business-critical changes.

@mvanhorn
Copy link
Copy Markdown
Contributor Author

mvanhorn commented May 5, 2026

Fixed in 9996e62 - backticked <Head> and <Tailwind> so the changelog renders them as inline code.

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.

Preview-server will crash if using dark:* classes in a Tailwind block

1 participant