DEV Community

Cover image for Get System Theme in JavaScript: Detect Dark/Light Mode Automatically
Amrendra kumar
Amrendra kumar

Posted on

Get System Theme in JavaScript: Detect Dark/Light Mode Automatically

Last month I was fixing a theme bug on a client project under our web development services, and the issue was frustrating. The site looked perfectly fine on my laptop, but a user on macOS with dark mode enabled complained about a blinding white flash every time the page loaded.

That single ticket taught me more about system theme detection than any tutorial ever did, and it is the reason I am writing this guide the way I wish someone had explained it to me back then.

If you are building a website or web app in 2026, respecting a visitor's operating system preference is no longer optional. Browsers, phones, and desktops all let users choose between light and dark mode at the system level, and modern users expect websites to follow that choice automatically instead of forcing them to hunt for a toggle button.

What Does "System Theme" Actually Mean

When someone switches their OS to dark mode, whether on Windows, macOS, Android, or iOS, that preference gets exposed to the browser through a CSS media feature called prefers-color-scheme. JavaScript can read this same signal using the window.matchMedia() API, which is built into every modern browser and needs no external library.

In short, you are not guessing the user's preference. You are reading a value the operating system already reports.

The Core Code Snippet

Here is the simplest way to check the current system preference:

const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

if (prefersDark) {
  document.documentElement.setAttribute('data-theme', 'dark');
} else {
  document.documentElement.setAttribute('data-theme', 'light');
}
Enter fullscreen mode Exit fullscreen mode

This single line does the heavy lifting. matchMedia returns a MediaQueryList object, and its matches property tells you whether the query currently applies. When I first used this in production, I was surprised how little code was actually required compared to the workarounds I had seen in older projects that relied on cookies or manual detection scripts.

Reacting to Live Theme Changes

A static check only tells you the preference at page load. Many users switch their system theme during the day, especially on laptops that auto-switch at sunset, so your site should react without needing a refresh. Add an event listener to the same media query object:

const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

mediaQuery.addEventListener('change', (event) => {
  const theme = event.matches ? 'dark' : 'light';
  document.documentElement.setAttribute('data-theme', theme);
});
Enter fullscreen mode Exit fullscreen mode

I added this listener to a SaaS dashboard we shipped earlier this year, and support tickets about "the site looks wrong" dropped noticeably because the interface now matched whatever the user's OS was doing in real time, without a manual reload.

Avoiding the Flash of Wrong Theme

One mistake I made early on was placing this detection script at the bottom of the page, right before the closing body tag. That caused a visible flash of the wrong theme for a split second before JavaScript ran. The fix is simple: put a small inline script in the document head, before any stylesheet loads, so the theme attribute is set before the browser paints anything.

<script>
  document.documentElement.setAttribute(
    'data-theme',
    window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  );
</script>
Enter fullscreen mode Exit fullscreen mode

This tiny change removed the flicker completely on every project where I applied it since.

Combining System Detection With a Manual Toggle

Detecting the system theme is only half the picture. Most users still expect a toggle button so they can override the OS setting for that specific site. If you want the full implementation, including how to store the user's manual choice with localStorage so it persists across visits, we covered that in detail in our guide on building a light and dark theme switch using JavaScript. Read that alongside this article if you need both automatic detection and a manual override in the same project.

Where This Fits Into Product Design

System theme detection is not just a coding exercise. It directly affects how polished a product feels to real users, which is why our UI/UX and product design work always includes theme handling as a baseline requirement, not an afterthought. A product that respects a user's system preference from the first paint feels considerably more trustworthy than one that ignores it.

Common Mistakes to Avoid

Based on the projects I have reviewed for clients, these are the errors that show up most often:

  • Checking the preference only once and never listening for changes, so the theme goes stale if the user switches mid-session.
  • Running the detection script after the CSS has already loaded, which causes the flash mentioned earlier.
  • Forgetting to remove the event listener when a component unmounts in frameworks like React, which can cause memory leaks on single-page applications.
  • Assuming matchMedia is always supported. It is available in every current browser, but a quick if (window.matchMedia) guard is still good defensive coding for older environments.

Testing Your Implementation Properly

Do not rely only on changing your OS setting to test this feature, since that is slow and easy to forget. Chrome, Firefox, and Safari all let you emulate prefers-color-scheme directly inside developer tools, which makes testing both states in seconds instead of minutes.

Final Thoughts

Reading the system theme in JavaScript takes only a few lines of code, but getting it right, without flicker, without stale state, and with proper cleanup, is what separates a rushed implementation from a genuinely polished one. This is the exact kind of detail we handle across our frontend development and React work at Code with Amrendra.

If you are working through a similar frontend challenge or want a second pair of eyes on your theming setup, browse more guides on our engineering blog or reach out through our contact page and we will be glad to help.

Top comments (0)