@zachleat/solar-eclipse-toggle
v2.2.1
Published
An accessible light/dark theme toggle button that follows your system preference by default.
Maintainers
Readme
<solar-eclipse-toggle> Web Component
An accessible light/dark theme toggle button that follows your system preference by default.
- Demo on GitHub Pages
Installation
npm install @zachleat/solar-eclipse-toggleInclude the stylesheet and the script on your web site:
<link rel="stylesheet" href="solar-eclipse-toggle.css">
<script type="module" src="solar-eclipse-toggle.js"></script>The stylesheet is also exported as @zachleat/solar-eclipse-toggle/style.css.
Usage
Define the icons once as reusable symbols (copy the full paths from demo.html):
<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden">
<symbol id="se-icon-moon" viewBox="0 0 512 512"><!-- Font Awesome moon --></symbol>
<symbol id="se-icon-sun" viewBox="0 -32 576 576"><!-- Font Awesome sun --></symbol>
<symbol id="se-icon-half" viewBox="0 0 512 512"><!-- Font Awesome circle-half-stroke --></symbol>
</svg>Then use the component markup:
<solar-eclipse-toggle>
<button type="button" disabled>
<span class="se-label-dark" hidden><svg aria-hidden="true"><use href="#se-icon-moon"/></svg>Use dark theme</span>
<span class="se-label-light" hidden><svg aria-hidden="true"><use href="#se-icon-sun"/></svg>Use light theme</span>
<span class="se-label-unknown"><svg aria-hidden="true"><use href="#se-icon-half"/></svg>Theme</span>
<span class="se-system">System</span>
</button>
</solar-eclipse-toggle>(<span class="se-system">System</span> is optional)
Add this to your <head> to apply a saved theme before first paint:
<script>
try {
var theme = localStorage.getItem("theme");
if(theme === "light" || theme === "dark") {
document.documentElement.setAttribute("data-theme", theme);
}
} catch(e) {}
</script>Write your dark styles for both the system preference and the override:
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
/* dark styles */
}
}
:root[data-theme="dark"] {
color-scheme: dark;
/* dark styles */
}Default theme
To ignore the system preference when there is no saved choice, add data-theme-default (light or dark) to the root element:
<html data-theme-default="dark">Use the same attribute in your own CSS to pick the page’s default colors:
:root {
color-scheme: dark;
/* dark styles */
}
:root[data-theme="light"] {
color-scheme: light;
/* light styles */
}Consider relabeling SYSTEM (e.g. <span class="se-system">Default</span>) and setting status-auto, which defaults to the default when a default theme is declared. See demo-default-dark.html.
Features
- Follows
prefers-color-schemeuntil a visitor picks the other theme, which is saved tolocalStorage. - Choosing the system theme again clears the saved override.
- A plain
<button>named for what it does next (“Use dark theme”), with noaria-pressedstate. - Announces the new theme in a
role="status"live region, since screen readers don’t reliably announce name changes. - Labels, icons, and the SYSTEM label switch with CSS, so the button width never changes.
- Before JavaScript runs (or without it), the button is disabled and shows
.se-label-unknownwith SYSTEM. - Without CSS, JavaScript swaps
hiddenfrom.se-label-unknownto the label for the other theme, and hides SYSTEM (if present) unless an override is active. - Multiple instances, other tabs, and live system preference changes all stay in sync.
Options
storage-key:localStoragekey. Default:themestatus-light,status-dark,status-auto: announcements. Defaults:Light theme on,Dark theme on,matching your system(orthe defaultwithdata-theme-default)- Listen for the bubbling
theme-changeevent, withevent.detailof{ theme, auto }. - Translate by editing the markup and the
status-*attributes.
Skip automatic definition
Add ?nodefine to the script URL to skip the customElements.define call:
<script type="module">
import { SolarEclipseToggle } from "./solar-eclipse-toggle.js?nodefine";
SolarEclipseToggle.define();
</script>The stylesheet targets the solar-eclipse-toggle tag name.
Styling
Styles are in the solar-eclipse-toggle cascade layer, so your own styles win. Colors use custom properties, with light and dark naming the current page theme:
--se-light-color,--se-light-border,--se-light-icon,--se-light-hover,--se-light-system-bg,--se-light-system-color--se-dark-color,--se-dark-border,--se-dark-icon,--se-dark-hover,--se-dark-system-bg,--se-dark-system-color--se-focus
Credits
Demo icons are Font Awesome Free (CC BY 4.0).
