Add an additional Dark Mode toggle that simulates prefers-color-scheme
#3609
Replies: 3 comments
|
Just going to share my current setup in case it's nuts (some of the documentation isn't there for the new Tailwind CSS variables feature): // BaseEmail.jsx
import { Body, Container, Head, Html, Preview, Section, Tailwind, type TailwindProps } from 'react-email';
import { baseTheme, tailwindConfig } from './theme';
export function BaseEmail({
theme = baseTheme,
locale = 'en',
preview,
children,
}) {
return (
<Tailwind config={tailwindConfig} theme={theme}>
<Html lang={locale}>
<Head>
<title>{EMAIL_BRAND_TITLE}</title>
<meta name="color-scheme" content="light dark" />
<meta name="supported-color-schemes" content="light dark" />
<style>{`
:root { color-scheme: light dark; }
@media (prefers-color-scheme: dark) {
.img-light { display: none !important; }
.img-dark { display: inline-block !important; }
}
`}</style>
// etc...
</Head>
{preview ? <Preview>{preview}</Preview> : null}
<Body className="m-0 p-0 bg-background dark:bg-background-dark font-sans font-extralight">
{*/ ...etc */}
</Body>
</Html>
</Tailwind>
);
}// theme.ts
import { pixelBasedPreset, type TailwindConfig, type TailwindProps } from 'react-email';
export const baseTheme: TailwindProps['theme'] = `
@theme {
/* ---- Colors: light (default) ---- */
--color-background: #f2f2f2;
--color-card: #F5F3EE;
--color-text: #131822;
/* ---- Colors: dark ---- */
--color-background-dark: #0a0e14;
--color-card-dark: #131822;
--color-text-dark: #FFFFFF;
/* ---- Type & sizing ---- */
// ...
}
`;
// Do not use the `theme` property in the config — tokens belong in the string
// above, passed to <Tailwind theme={tailwindTheme} />.
export const tailwindConfig: TailwindConfig = {
// rem is not supported in some email clients
presets: [pixelBasedPreset],
};Again, as far as I can tell from sending test emails with Resend this all seems to work! It's just an issue with the preview ui. I appreciate your time looking at all of this 😅 |
|
Went and read the actual toggle implementation ( Your proposed approach is sound and fits the existing pattern well. The function applyPrefersDarkEmulation(iframe) {
const doc = iframe.contentDocument;
if (!doc) return;
let css = '';
for (const sheet of doc.styleSheets) {
for (const rule of sheet.cssRules) {
if (rule instanceof CSSMediaRule && rule.media.mediaText.includes('prefers-color-scheme: dark')) {
for (const inner of rule.cssRules) css += `${inner.cssText}\n`;
}
}
}
const style = doc.createElement('style');
style.setAttribute('data-emulated-prefers-dark', '');
style.textContent = css;
doc.head.appendChild(style);
}No cross-origin |
|
Both goals from the original post are covered in #3712: there is now a mode that renders the dark styles the email defines, and the two behaviors are separate controls with tooltips naming which clients do which, so the existing toggle is no longer ambiguous. Thanks for the write-up and the screenshots; the Apple Mail comparison made the gap easy to pin down. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Goals
Background
As I understand, the preview's dark-mode toggle simulates forced color inversion but does not emulate
@media (prefers-color-scheme: dark). As a result, emails that explicitly implement dark mode styles can't be previewed at all (seems to be a 50/50 split of which approach email clients take if I understand correctly).The existing toggle silently shows an inverted version of the light styles instead of the authored dark styles.
Light mode in Preview:

Toggle dark mode in Preview:

System dark mode set in Preview:

System dark mode set in Apple Mail:

To not bloat this initial post anymore I am going to post my code setup in a reply (it is using the newly released tailwind 4 theme variables support)
Proposal
Add a prefers-color-scheme: dark emulation mode next to the existing button. Since the media query can't be forced from app code, do it by CSS rewrite on the already-loaded iframe:
(This proposal is from Claude, I'm not as familiar with dark mode styling or dealing with email HTML nearly as much as you all)
Sketch:
All reactions