It’s 2025, and we’re still building dark mode toggles with JavaScript like it’s 2019. This is a UX oversight. Mode preference — light or dark — is a personal, system-level setting, and browsers already know how to handle it. Yet, websites keep reinventing the wheel with janky toggles that often don’t persist, don’t sync with system changes, and can’t even influence CSS media queries. The result? Inconsistent UX, broken themes, and wasted developer time — all to replicate something that should be a native browser feature, just like zoom or autoplay controls.
There are plenty of practical and technical reasons why theme switching belongs in the browser, not in your app code. Here’s a breakdown of why this shift would be a win for users, developers, and the web platform as a whole:
Native switches could be surfaced consistently across all sites, making them easier to find and use — especially for users relying on keyboard shortcuts or assistive tech.
When dark mode toggles are implemented site-by-site, users have to hunt for them — sometimes they’re in a menu, sometimes buried in settings, or missing entirely. A browser-native switch would standardize the location and interaction, making it easier for everyone, especially users with motor or cognitive impairments. For example, just like Cmd +
universally zooms the page, there could be a shortcut to toggle dark mode for the current site. This consistent affordance would also benefit power users and keyboard navigators. It’s the same principle that made native zoom controls render custom font size switchers obsolete.
Modern browsers already support dark mode detection through prefers-color-scheme
, and all major dev tools include a dark mode toggle to simulate it. This means the underlying machinery for switching modes exists — it’s just not exposed to users in a persistent, per-site way. Meanwhile, browsers support per-site settings like zoom, audio muting, and notifications. Adding a dark mode preference wouldn’t require new standards — just UI to expose what’s already technically possible.
Browsers already show per-site preferences as icons in the address bar. A dark mode toggle fits naturally here — consistent, discoverable, and free of site-specific implementations.
JavaScript dark mode toggles can’t update prefers-color-scheme
, which severely limits their usefulness. Because of this, elements like <picture>
can’t dynamically swap images based on theme, and <svg>
files only respond to dark mode when inlined — defeating modularity.
<!-- This will always use the system's preference and can't be changed via JS -->
<picture>
<source srcset="./dark.svg" media="(prefers-color-scheme: dark)">
<img src="./light.svg" alt="Theme-aware image">
</picture>
Similarly, CSS features like @media (prefers-color-scheme)
and light-dark()
lose power when users can’t toggle the preference. A native, browser-managed switch would unlock the full potential of these platform features.
/* The light-dark function simplifies theme-aware styling but can't be controlled by JS toggles. */
.card {
background-color: light-dark(white, black);
color: light-dark(black, white);
}
Most sites toggle a dark or light class on the <html>
or <body>
element using JavaScript. This usually involves storing the user’s choice in localStorage and applying the class on load. It’s simple in theory, but fragile in practice. If the JS runs too late, users get a flash of the wrong theme — the infamous “flashbang” effect.
Others listen to window.matchMedia('(prefers-color-scheme: dark)')
and react to system-level theme changes. While functional, it doesn’t support user overrides well, and many sites skip it altogether.
And it's not a skill issue either. Even large platforms like YouTube and Google struggle with this. Due to custom logic, these sites often fail to respond immediately to system-level changes, with Google sometimes requiring a page refresh to apply the updated theme.
Some solve the flashbang by inlining the preference into initial HTML via cookies or headers. But this causes cache fragmentation — pages may need to render differently per user, complicating CDN strategies.
All of these approaches work around the platform instead of with it. Letting the browser manage theme switching would eliminate this complexity and lead to cleaner, more maintainable code.
Manually implementing theme toggles across projects is repetitive and error-prone. Every site reinvents the same logic — detection, persistence, DOM updates, CSS overrides — just to support a feature that belongs in the platform. Moving dark mode to the browser lets developers focus on styling, not infrastructure.
Dark mode is more than just a visual preference — it’s a core part of the user experience. Browsers already know the user's theme preference, and giving users the power to persist or override it per site — just like zoom or autoplay — would bring consistency, accessibility, and simplicity across the web.
By moving theme switching to the browser, we can create a more consistent, accessible, and developer-friendly web. It’s time to stop duct-taping dark mode with JavaScript and start treating it like the browser-native setting it is. Let’s embrace the tools the platform already provides and focus on building better experiences for everyone.