Web Component that toggles dark mode 🌒
npm install dark-mode-toggle Element
A custom element that allows you to easily put a _Dark Mode 🌒_ toggle or switch
on your site, so you can initially adhere to your users' preferences according
toprefers-color-scheme,
but also allow them to (optionally permanently) override their system setting
for just your site.
📚 Read all(!) about dark mode in the related article
Hello Darkness, My Old Friend.
Install from npm:
``bash`
npm install --save dark-mode-toggle
Or, alternatively, use a
`
!Dark mode toggle live coding sample.
(See the original HD version so you can pause.)
There are three ways how you can use :
The custom element assumes that you have organized your CSS in different files
that you load conditionally based on the media attribute in the
stylesheet's corresponding link element. This is a great performance pattern,
as you don't force people to download CSS that they don't need based on their
current theme preference, yet non-matching stylesheets still get loaded, but
don't compete for bandwidth in the critical rendering path. You can also have
more than one file per theme. The example below illustrates the principle.
` Check out the dark mode toggle in the upper right corner!html`
rel="stylesheet"
href="light.css"
media="(prefers-color-scheme: light)"
/>
type="module"
src="https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs"
>
Hi there
src="https://googlechromelabs.github.io/dark-mode-toggle/demo/cat.jpg"
alt="Sitting cat in front of a tree"
width="320"
height="195"
/>
The above method might cause flashing
(#77) when the
page loads, as the dark mode toggle module is loaded after the page is rendered.
A loader script can be used to apply the saved theme before the page is
rendered. Wrap the stylesheet tags with and add the loader
script as follows:
`html`
type="module"
src="https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs"
>
If you prefer to not split your CSS in different files based on the color
scheme, you can instead work with a class that you toggle, for example
class="dark". You can see this in action in
this demo.
`js
import * as DarkModeToggle from 'https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs';
const toggle = document.querySelector('dark-mode-toggle');
const body = document.body;
// Set or remove the dark class the first time.
toggle.mode === 'dark'
? body.classList.add('dark')
: body.classList.remove('dark');
// Listen for toggle changes (which includes prefers-color-scheme changes)dark
// and toggle the class accordingly.`
toggle.addEventListener('colorschemechange', () => {
body.classList.toggle('dark', toggle.mode === 'dark');
});
This approach allows you to define styles directly within your HTML using
type="module"
src="https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs"
>
`
See the custom element in action in the
interactive demo.
It shows four different kinds of synchronized s. If you use
Chrome on an Android device, pay attention to the address bar's theme color, and
also note how the favicon changes.


Properties can be set directly on the custom element at creation time, or
dynamically via JavaScript.
👉 Note that the dark and light icons are set via CSS variables, see
Style Customization below.
| Name | Required | Values | Default | Description |
| ------------ | -------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| mode | No | Any of "dark" or "light" | Defaults to whatever the user's preferred color scheme is according to prefers-color-scheme, or "light" if the user's browser doesn't support the media query. | If set overrides the user's preferred color scheme. |appearance
| | No | Any of "toggle" or "switch" | Defaults to "toggle". | The "switch" appearance conveys the idea of a theme switcher (light/dark), whereas "toggle" conveys the idea of a dark mode toggle (on/off). |permanent
| | No | true if present | Defaults to not remember the last choice. | If present remembers the last selected mode ("dark" or "light"), which allows the user to permanently override their usual preferred color scheme. |legend
| | No | Any string | Defaults to no legend. | Any string value that represents the legend for the toggle or switch. |light
| | No | Any string | Defaults to no label. | Any string value that represents the label for the "light" mode. |dark
| | No | Any string | Defaults to no label. | Any string value that represents the label for the "dark" mode. |remember
| | No | Any string | Defaults to no label. | Any string value that represents the label for the "remember the last selected mode" functionality. |
- colorschemechange: Fired when the color scheme gets changed.permanentcolorscheme
- : Fired when the color scheme should be permanently
remembered or not.
Interacting with the custom element:
`js
/ On the page /
const darkModeToggle = document.querySelector('dark-mode-toggle');
// Set the mode to dark
darkModeToggle.mode = 'dark';
// Set the mode to light
darkModeToggle.mode = 'light';
// Set the legend to "Dark Mode"
darkModeToggle.legend = 'Dark Mode';
// Set the light label to "off"
darkModeToggle.light = 'off';
// Set the dark label to "on"
darkModeToggle.dark = 'on';
// Set the appearance to resemble a switch (theme: light/dark)
darkModeToggle.appearance = 'switch';
// Set the appearance to resemble a toggle (dark mode: on/off)
darkModeToggle.appearance = 'toggle';
// Set a "remember the last selected mode" label
darkModeToggle.remember = 'Remember this';
// Remember the user's last color scheme choice
darkModeToggle.setAttribute('permanent', '');
// Forget the user's last color scheme choice
darkModeToggle.removeAttribute('permanent');
`
Reacting on color scheme changes:
`jsColor scheme changed to ${e.detail.colorScheme}.
/ On the page /
document.addEventListener('colorschemechange', (e) => {
console.log();`
});
Reacting on "remember the last selected mode" functionality changes:
`js${e.detail.permanent ? 'R' : 'Not r'}emembering the last selected mode.
/ On the page /
document.addEventListener('permanentcolorscheme', (e) => {
console.log(
,`
);
});
You can style the custom element with
::part(). See the
demo's
CSS source code
for some concrete examples. The exposed parts and their names can be seen below:
`html`
Additionally, you can use a number of exposed CSS variables, as listed in the
following:
| CSS Variable Name | Default | Description |
| ------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| --dark-mode-toggle-light-icon | No icon | The icon for the light state in background-image: notation. |--dark-mode-toggle-dark-icon
| | No icon | The icon for the dark state in background-image: notation. |--dark-mode-toggle-icon-size
| | 1rem | The icon size in CSS length data type notation. |--dark-mode-toggle-remember-icon-checked
| | No icon | The icon for the checked "remember the last selected mode" functionality in background-image: notation. |--dark-mode-toggle-remember-icon-unchecked
| | No icon | The icon for the unchecked "remember the last selected mode" functionality in background-image: notation. |--dark-mode-toggle-color
| | User-Agent stylesheet text color | The main text color in color: notation. |--dark-mode-toggle-background-color
| | User-Agent stylesheet background color | The main background color in background-color: notation. |--dark-mode-toggle-legend-font
| | User-Agent
The core custom element code lives in
src/dark-mode-toggle.mjs.
You can start hacking and testing your changes by running npm run start andnpm publish
then navigating to
this happens automatically upon ing. If for whatever reason younpm run build
want to build locally, run . You can lint by runningnpm run lint.
The HTML and the CSS used by is hard-coded as a templatesrc/dark-mode-toggle.mjs
literal in the file . For optimal performance, thesrc/template-contents.tpl
contents of this literal are hand-minified. If you need to tweak the HTML or the
CSS, find the unminified template literal contents in and copy them over to src/dark-mode-toggle.mjs.*.tpl
Once your changes are done, commit them to both the file (in unminified*.mjs
form) and the file (in minified form).
(This is actually just making a strong argument for
CSS Modules and
HTML Modules that would allow
for proper tools integration).
- v8.dev: V8 is Google’s open source high-performance
JavaScript and WebAssembly engine, written in C++.
- Your site here…
This is not an official Google product.
Thanks to all
contributors
for making
Tomek Sułkowski.
Copyright 2019 Google LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.