Create a themed favicon for color modes
Tags: javascript, react, reacthooks, npm
Published: 2021-09-29 23:21:23

> There are 2 types of people in this world. Those who use dark mode and the other people.

I'm not sure about you, but I am basically a 100% user of dark mode on everything I do. There is nothing worse then sitting down at my desk to do some work or reading, opening a website and being hit with a solar flare from the bright white screen in front of me. However, this has caused me some issues when it comes to `favicons` on the web. A favicon is the small icon that you see in your browser tab that allows you to navigate the madness of your many tabs. If your like me and prefer to save your eyes from the blinding brightness of light mode, you may have noticed that some of these `favicons` are kind of hard to see.

![The current favicon on my personal website](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0xzjta8n1l0ymazek95.png)

In this post we will go over how to toggle your favicon based on whether the user has their settings on `dark mode` or `light mode`. 

**Note:** In this example I will be using a [NextJS](https://nextjs.org/) website, however this will work in any React application.

## Lets start

### Create our project

First thing we will do is create a new project.

```bash
npx create-next-app themeable-favicons
```

### Create a custom hook

Next, we are going to create a [custom hook](https://reactjs.org/docs/hooks-intro.html) called `useSystemTheme`. For our custom hook we are going to simply wrap an already created npm package. So lets install the package.

```bash
npm install react-use-system-theme
```

Now let's create a new file called `useSystemTheme.js` under a `hooks` directory. Our directory structure should look something like this.

```
│   └── components
│   └── hooks
|       ├── useSystemTheme.js
│   └── pages
|       ├── index.js
```

Inside our `useSystemTheme.js` file, we are going to import the `useTheme` function from our `react-use-system-theme` and return the value from it.

```js
// useSystemTheme.js
import useTheme from 'react-use-system-theme';

export function useSystemTheme() {
  const theme = useTheme();
  return theme;
}
```

This is called "wrapping". The reason that we want to take this approach rather than just using the `useTheme` function directly is that if in the future, we decide to re-write this hook or use a different package, we will only need to make the change in one place.

### Create our favicons

Next we want to create our favicons. I like to use [RealFaviconGenerator.net](https://realfavicongenerator.net/) as I think that it gives you the most robust options for your favicons.

Once you have created your two favicon packages (one for your dark mode and one for your light mode), you will want to rename the files in them from `favicon.ico` -> `favicon-dark.ico` etc.

```
│   └── public
|       ├── favicon-dark-16x16.png
|       ├── favicon-dark-32x32.png
|       ├── favicon-dark.ico
|       ├── favicon-light-16x16.png
|       ├── favicon-light-32x32.png
|       ├── favicon-light.ico
```

### Use our hook to toggle favicons

**Note:** This step will be very specific to how NextJS works. However, you can do the same thing in any project that has a `favicon`.

By default, NextJS adds a favicon to our `pages/index.js` file. We will want to go in and remove this, as we are going to move the favicon to our `pages/_app.js` file.

Next, in our `pages/_app.js` file we will want to include our `favicon`. To do this, we are going to import the `Head` component from `next/head`. This will allow us to add to our `html` `head` tag.

Inside of our `Head` component, we will want to add our `favicon` that we removed from our `pages/index.js`.

```jsx
import Head from "next/head";
import "../styles/globals.css";

function MyApp({ Component, pageProps }) {
  return (
    <>
      <Head>
        <link rel="icon" href={`/favicon-${theme}.ico`} />
      </Head>
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;
```

Finally, we want to import and use our hook to toggle between the two `favicons`.

```tsx
import Head from "next/head";
import { useSystemTheme } from "../hooks/useSystemTheme";
import "../styles/globals.css";

function MyApp({ Component, pageProps }) {
  const theme = useSystemTheme();
  return (
    <>
      <Head>
        <link rel="icon" href={`/favicon-${theme}.ico`} />
      </Head>
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;
```

You will see in the code above that I am including the `favicon` with `favicon-${theme}.ico`. This will use the dark favicon that we created earlier on.

Now, when we switch our system theme from light mode, to the more appropriate dark mode, we will be able to toggle our favicon with it.

### Some extra notes

- While this technique works for system preferences, it can also be used with different color themes if you use something like [Theme UI](https://theme-ui.com/) or [Chakra UI](https://chakra-ui.com/).
- You can find an example repo of this working [here](https://github.com/eddysims/color-themed-favicons)
- You can find a working demo [here](https://themed-favicons.netlify.app/)
- You can find this content in video form [here](https://www.youtube.com/watch?v=kDl2dU4D8kg&t=18s)