Home

Light/Dark Mode Favicon for React Sites

Toggle between two favicon images based on the user’s current theme (color scheme).

I have a Next.js (React) project where I wanted to adjust the favicon based on whether the current user is in dark or light mode.

Here’s a generic version of what I implemented. It is commented to add some context, and you can find additional context below the snippet.

import { useEffect, useState } from "react";
import { Helmet } from "react-helmet";

/**
* Returns the path for a favicon based on the given color scheme.
*
* @param {boolean} isDarkMode If currently in dark mode
*/

const getFaviconPath = (isDarkMode = false) => {
return `/favicon-${isDarkMode ? "dark" : "light"}.png`;
};

export default function MyApp() {
const [faviconHref, setFaviconHref] = useState("/favicon-light.png");

useEffect(() => {
// Get current color scheme.
const matcher = window.matchMedia("(prefers-color-scheme: dark)");
// Set favicon initially.
setFaviconHref(getFaviconPath(matcher.matches));
// Change favicon if the color scheme changes.
matcher.onchange = () => setFaviconHref(getFaviconPath(matcher.matches));
}, [faviconHref]);

return (
<>
<Helmet>
<link rel="icon" href={faviconHref} />
{/* Other meta tags ... */}
</Helmet>

{/* Page content ... */}
</>
);
}

Here are the key elements to note:

  • The image files are favicon-light.png and favicon-dark.png, where the “dark” image applies to the dark mode.
  • I am using the light mode icon as the default. This is because: 1) light is the default on most machines, and 2) browser support is limited and it’s the natural fallback. (More on this below.)
  • useEffect is used to ensure that window is available. And it runs only when the component is mounted, updated, or is about to be unmounted. Learn more about the effect hook.

Here’s a demo of the result:

Limited Browser Support

The browser support for prefers-color-scheme is limited. This is why I mention using the light image as the default.

Some browsers have their own behavior. For example, Safari puts white box behind the icon when in dark mode so there’s no need to adjust.

Let's Connect

Keep Reading

When to Check for Broken Links

Explore various methods for checking for broken links and what to consider when applying the approaches to your site.

Apr 19, 2023

Simple Content Tab with React and Tailwind

The foundation for a tab system begins with a state hook, triggered by clicks on tab elements. View the code snippet and use the playground to see it in action.

May 28, 2022

Taking a Balanced Approach to New Technology

"New" is a dangerous word in the tech world. With so much changing every day, how do we make sure we know which tools and technologies to invest our time in and which ones to leave behind?

Feb 01, 2019