Â
Â
🕯 Make your favicon adapt to dark and light mode
Â
Â
Â
Â
You can install favicon-mode-switcher
using the package manager of your choice or load it through a CDN:
npm:
npm install favicon-mode-switcher
yarn:
yarn add favicon-mode-switcher
CDN (unpkg):
<script type="module">
import faviconModeSwitcher from 'https://unpkg.com/favicon-mode-switcher/dist/index.min.mjs'
// ...
</script>
or the UMD build:
<script src="https://unpkg.com/favicon-mode-switcher">
💡 Since all browsers supporting
(prefers-color-scheme)
also support JavaScript modules, usage of the module version is highly recommended. The UMD build is only meant for scenarios where you can't use<script type="module">
, for example when inserting the script using a WordPress hook.
Â
import faviconModeSwitcher from 'favicon-mode-switcher'
// or
const faviconModeSwitcher = require('favicon-mode-switcher')
// or
const faviconModeSwitcher = window.faviconModeSwitcher.default
// then...
faviconModeSwitcher('link[rel="shortcut icon"]')
// or
faviconModeSwitcher(document.querySelector('#favicon'))
// or
faviconModeSwitcher({
element: document.querySelector('#favicon'),
href: { dark: '/icons/favicon-light.ico' },
})
Â
The module exports a single function as default export. If the UMD build is used, this function will be exposed on window.faviconModeSwitcher.default
. It has the following type signature:
function faviconModeSwitcher(FaviconTarget | FaviconTarget[] | NodeListOf<HTMLLinkElement>): DestroyFunction
It takes either the configuration for a single icon to be updated, or an Array containing multiple configurations if you want to keep many icons in sync with the active color scheme. NodeList
is supported too, so you can use it with document.querySelectorAll()
.
🕯 Even though it's technically not an icon, you can also update the web app manifest (
<link rel="manifest">
) of your website usingfavicon-mode-switcher
!
The configuration for an icon is either:
- a CSS selector string, which has to return a
<link>
element when passed todocument.querySelector()
- a
<link>
element itself - an Object, containing one of the above as the
element
property, along with an optionalhref
config
type FaviconTarget =
| string
| HTMLLinkElement
| {
element: string | HTMLLinkElement
href?: { dark?: string; light?: string }
}
Â
If you use a selector, Element or Object without href
property as icon config, the icon's href
will be updated automatically.
For this, favicon-mode-switcher
will look for the substring "dark" or "light" in the href
you specified in the HTML and replace it with the currently active color scheme.
For example: here, the href
will be replaced with ./my-favicon.dark.ico
whenever the device is in dark mode:
<link rel="shortcut icon" href="./my-favicon.light.ico" />
(if the href
in the HTML doesn't contain either "light"
or "dark"
, nothing will happen)
Â
Alternatively, you can specify href
configuration when using an Object. The object keys must match a color scheme and the value is the href
that should be used when the color scheme from the key is active.
For example: with the following config the href
of <link id="icon">
will be set to ./logo-teal.ico
while the device is in dark mode, and logo-navyblue.ico
while the device is in light mode.
{ element: '#icon', href: { dark: './logo-teal.ico', light: './logo-navyblue.ico' } }
However, you only need to specify the href
for one color scheme:
If there is no href
defined for the color scheme that is currently active, favicon-mode-switcher
will simply use the one that was initially specified in the HTML.
Â
The main function described above returns a destroy function when called. Run it and the switcher will stop and reset all the icons to their original href
:
const destroyIconSwitcher = faviconModeSwitcher(document.querySelectorAll('.favicon'))
// later...
destroyIconSwitcher()
Â
Detecting the active color scheme is a relatively new feature and as such has limited browser support. The script itself should run in any browser from at least Internet Explorer 9 upwards without throwing an error, so you can use it for Progressive Enhancement.
It also doesn't throw if window
is undefined
, so you can safely require and execute it in a Node environment for SSR.
Note that the ESModule versions (.mjs
file extension) only work in browsers with support for ES2015 / ES6
. Modern bundlers like webpack will automatically import these versions by default. If you're using such a bundler and need legacy browser support, either transpile the module yourself or directly import the CommonJS version at dist/index.js
.
Â
Â
Â
PRs welcome!
Â
© 2021, Jonas Kuske