Theme switch
A manual theme switch component that respects a user's preference for light or dark mode viewing.
Requirements (anchor)
Requires the script loaded in the <head>
prior to the CSS negates FOUC when changing or refreshing pages, the HTML button with the same attributes as the example below.
JS
Adapted Adam Argyle's Building a theme switch component script to use an inline style on the <html>
attribute.
const storageKey = "theme-preference",
onClick = () => {
(theme.value = "light" === theme.value ? "dark" : "light"),
setPreference();
},
getColorPreference = () => (localStorage.getItem(storageKey)
? localStorage.getItem(storageKey)
: window.matchMedia("(prefers-color-scheme: dark)")
.matches ? "dark" : "light"),
setPreference = () => {
localStorage.setItem(storageKey, theme.value),
reflectPreference();
},
reflectPreference = () => {
document.firstElementChild.style.setProperty("color-scheme", theme.value);
},
theme = {
value: getColorPreference()
};
reflectPreference(),
(window.onload = () => {
reflectPreference(),
document.querySelector("#themes").addEventListener("click", onClick);
}),
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({matches: e}) => {
(theme.value = e ? "true" : "false"),
setPreference();
});
<button id="themes">Theme switch</button>
The script detects a users viewing preference plus remembers the selection made if using the switch button, it then adds inline color-scheme
style attributes to the <html>
tag depending on the current color-scheme.
// If light
<html lang="en" style="color-scheme: light;">
// If dark
<html lang="en" style="color-scheme: dark;">
Without extra CSS the user-agent light and dark mode styles will be used and as demonstrated with some of the StyleMods styles the user-agent colors can be applied with CSS color-mix()
values for consistent site styling.
Using the module (anchor)
To use the module load the StyleMods scss
directory as follows (changing the path to suit the source files location as required) then include the Sass mixin anywhere below.
@use "stylemods/scss" as *;
@include theme-switch-css;
Source code (anchor)
theme-switch.scss
The icon styles with the theme switch replicate those included with the icons which can also be used in conjunction with the theme switch styles if preferred.
// ----------------------------------------------------------
// Theme switch
// ----------------------------------------------------------
$light-scheme-icon: url("data:image/svg+xml,<svg viewBox='0 0 16 16' fill='currentColor' xmlns='http://www.w3.org/2000/svg'><path d='m7.47 0v2.26h1.15v-2.26zm-4.9 2.19-0.812 0.8 1.62 1.6 0.812-0.8zm10.8 0-1.62 1.6 0.812 0.8 1.62-1.6zm-5.29 1.25s-4.59 0-4.59 4.52c0 4.52 4.59 4.52 4.59 4.52s4.59 0 4.59-4.52c0-4.52-4.59-4.52-4.59-4.52zm5.67 3.92v1.13h2.3v-1.13zm-13.7 0.0243v1.13h2.3v-1.13zm3.01 4-1.62 1.6 0.812 0.8 1.62-1.6zm9.99 0-0.812 0.8 1.62 1.6 0.812-0.8zm-5.54 2.36v2.26h1.15v-2.26z'/></svg>") !default;
$dark-scheme-icon: url("data:image/svg+xml,<svg viewBox='0 0 16 16' fill='currentColor' xmlns='http://www.w3.org/2000/svg'><path d='m5.27 1c-0.533 0.0926-0.946 0.529-1.39 0.815-1.17 0.88-1.95 2.19-2.46 3.54-0.777 2.03-0.429 4.41 0.861 6.16 1.41 1.98 3.67 3.56 6.18 3.49 1.98-0.0388 3.86-0.991 5.28-2.33 0.48-0.565 0.971-1.16 1.27-1.84 0.089-0.435-0.481-0.742-0.809-0.456-1.61 0.937-3.67 1.22-5.37 0.365-1.52-0.764-2.79-2.04-3.55-3.55-0.871-1.73-0.56-3.83 0.411-5.45 0.187-0.304-0.0437-0.726-0.4-0.734z'/></svg>") !default;
@mixin theme-switch-css {
[style="color-scheme: light;"] #themes {
--svg: #{$light-scheme-icon};
}
[style="color-scheme: dark;"] #themes {
--svg: #{$dark-scheme-icon};
}
#themes:before {
display: inline-block;
content: "";
block-size: 1em;
inline-size: 1em;
vertical-align: -.12em;
background-color: var(--ico, buttontext);
mask-image: var(--svg);
mask-repeat: no-repeat;
}
#themes span {
position: absolute;
block-size: 1px;
inline-size: 1px;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
} // end theme-switch-css