Skip to content

Conversation

@gabrielmfern
Copy link
Member

@gabrielmfern gabrielmfern commented Oct 23, 2025

This goes off of the previous work done by @KayleeWilliams in #1749. But, instead of adapting the color-scheme in the email template, it emulates email client behavior by flipping the lightness of colors, also reversing the order of the calculation when done for foreground.

We might also want to improve the images we have in static for the demo, since they seem quite bad when using the new emulation. We also might want a better design touch, mainly for a way to tell users the dark mode is just an emulation, and not exactly what email clients do.

How to use this?

  1. Install react-email@canary
  2. Install https://pkg.pr.new/resend/react-email/@react-email/preview-server@2589
  3. Run email dev and see http://localhost:300

or checkout the demo preview deploy for this, which also works!


Summary by cubic

Adds a dark mode switcher to the preview server that emulates email client color inversion for more realistic dark mode previews. Users can toggle light/dark in the topbar; the theme persists via URL.

  • New Features

    • Theme toggle in the topbar with sun/moon icons.
    • EmailFrame applies color inversion to text, backgrounds, and borders using the Color library; iframe is keyed by theme and re-inverts on load.
    • Theme state synced to the ?theme= URL param.
  • Dependencies

    • Added color@5.0.2.

KayleeWilliams and others added 19 commits October 15, 2025 16:35
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: gabriel miranda <gabrielmfern@outlook.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bu Kinoshita <6929565+bukinoshita@users.noreply.github.com>
Co-authored-by: gabriel miranda <gabrielmfern@outlook.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Bu Kinoshita <6929565+bukinoshita@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@gabrielmfern gabrielmfern self-assigned this Oct 23, 2025
@changeset-bot
Copy link

changeset-bot bot commented Oct 23, 2025

🦋 Changeset detected

Latest commit: 0dfa391

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

This PR includes changesets to release 2 packages
Name Type
@react-email/preview-server Minor
react-email Minor

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

vercel bot commented Oct 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
react-email Ready Ready Preview Comment Oct 29, 2025 7:00pm
react-email-demo Ready Ready Preview Comment Oct 29, 2025 7:00pm

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 23, 2025

Open in StackBlitz

npm i https://pkg.pr.new/resend/react-email/@react-email/preview-server@2589

commit: 0dfa391

Copy link
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.

5 issues found across 9 files

Prompt for AI agents (all 5 issues)

Understand the root cause of the following 5 issues and fix them.


<file name="packages/preview-server/src/app/preview/[...slug]/email-frame.tsx">

<violation number="1" location="packages/preview-server/src/app/preview/[...slug]/email-frame.tsx:5">
Rule violated: **Initialisms and Acronyms Naming Conventions**

Rename `walkDOM` to `walkDom` (and update its usages) so the DOM acronym follows the camel-cased initialism convention required for identifiers.</violation>

<violation number="2" location="packages/preview-server/src/app/preview/[...slug]/email-frame.tsx:32">
The hex-matching branch in `colorRegex` accepts invalid values (e.g., it matches `#pattern`), which causes `Color()` to throw during dark-mode inversion. Tighten the regex to only match legitimate hex colors (e.g., `{3,4,6,8}` with `[0-9a-fA-F]`).</violation>
</file>

<file name="packages/preview-server/src/app/preview/[...slug]/preview.tsx">

<violation number="1" location="packages/preview-server/src/app/preview/[...slug]/preview.tsx:45">
Preserve the existing URL hash when toggling the theme so the preview doesn’t lose the current anchor/scroll position.</violation>
</file>

<file name="packages/preview-server/src/components/topbar/theme-toggle-group.tsx">

<violation number="1" location="packages/preview-server/src/components/topbar/theme-toggle-group.tsx:31">
This icon-only toggle button lacks an accessible name, so screen reader users cannot tell it switches to the light theme. Add an aria-label or visually hidden text to give the control an accessible name.</violation>
</file>

<file name="packages/preview-server/package.json">

<violation number="1" location="packages/preview-server/package.json:35">
Please add @types/color alongside this new dependency; without declaration files, TypeScript reports TS7016 (&#39;Could not find a declaration file for module &quot;color&quot;&#39;) when checking email-frame.tsx.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

@gabrielmfern gabrielmfern merged commit 95c7417 into canary Oct 30, 2025
15 checks passed
@gabrielmfern gabrielmfern deleted the feat/dark-mode-switcher branch October 30, 2025 15:18
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.

6 participants