You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Preview dark mode toggle only inverts inline colors, never renders actual prefers-color-scheme styles #3707
I read through the preview's dark mode toggle implementation (packages/ui/src/app/preview/[...slug]/email-frame.tsx) after seeing #3609, and the toggle can't render an email's actual @media (prefers-color-scheme: dark) styles at all, only simulate one.
applyColorInversion/undoColorInversion walk the iframe DOM and invert inline style colors element by element:
It never touches <style> tags or evaluates any @media query. For any email that ships real prefers-color-scheme: dark rules in a <style> block, which is most dark-mode-aware markup, including anything using Tailwind's dark: classes, the toggle shows a color-inverted version of the light styles instead of the email's actual authored dark styles. There's no way in the preview UI today to see what the email genuinely looks like in a client that respects prefers-color-scheme (Apple Mail, etc).
Reproduction
Author an email with <style>{'@media (prefers-color-scheme: dark) { .card { background: #111 } }'}</style> (or the Tailwind dark: equivalent).
Open it in the preview and toggle dark mode.
Compare against opening the same rendered HTML directly in a mail client (or a browser tab with OS dark mode forced) that actually evaluates prefers-color-scheme.
The preview shows an inverted light theme; the real dark-mode styles never apply.
Suggested fix
The iframe is already rendered with sandbox="allow-same-origin ..." and srcDoc content (same origin as the parent app), which applyColorInversion itself relies on to reach into contentDocument directly. The same access works for reading doc.styleSheets, collecting rules inside a CSSMediaRule whose media.mediaText includes prefers-color-scheme: dark, and injecting their unwrapped cssText into a single <style> appended to the iframe's <head> when the toggle is on (removing it when toggled off). That would render the email's actual authored dark theme instead of a simulated inversion, matching what Apple Mail / Outlook for Mac do.
Happy to put together a PR for this if it's a direction the team wants, I already have a rough implementation sketched out against email-frame.tsx.
It ended up a little different from the sketch: where the browser propagates color-scheme into the frame (Firefox 105+, Chromium 129+) the email's own rules match untouched, and where it doesn't — Safari today — each prefers-color-scheme condition has its value flipped in place, rather than the rules being lifted into an appended <style>. That keeps them in their original cascade position and handles prefers-color-scheme: light blocks too.
The toggle is now two controls, one per client behavior, so the inversion emulation stays and is labelled for what it does.
This was a conscious decision since the idea of this feature is exactly to help you build an email that will work without media queries, as most email clients don't support them. I think we would be open to supporting both types of dark modes: one that only changes to dark mode for media queries, and the other that simulates email clients.
That being said, this isn't a bug, so I'm going to close this. Feel free to open a discussion where we can talk more about how to implement a way for this.
Activity
creativoma commentedon Aug 18, 2026
Opened #3712 for this.
It ended up a little different from the sketch: where the browser propagates
color-schemeinto the frame (Firefox 105+, Chromium 129+) the email's own rules match untouched, and where it doesn't — Safari today — eachprefers-color-schemecondition has its value flipped in place, rather than the rules being lifted into an appended<style>. That keeps them in their original cascade position and handlesprefers-color-scheme: lightblocks too.The toggle is now two controls, one per client behavior, so the inversion emulation stays and is labelled for what it does.
gabrielmfern commentedon Aug 25, 2026
This was a conscious decision since the idea of this feature is exactly to help you build an email that will work without media queries, as most email clients don't support them. I think we would be open to supporting both types of dark modes: one that only changes to dark mode for media queries, and the other that simulates email clients.
That being said, this isn't a bug, so I'm going to close this. Feel free to open a discussion where we can talk more about how to implement a way for this.