When designing my digital garden, I knew I wanted a cute dark mode toggle. Once I had drawn my SVG, I started building a web component that had all the same functionality as my dark mode toggle in React. This includes everything I learned while accessibility auditing my site.
In addition to changing the theme, the toggle needs to take the user's prefers-color-scheme selection into account and persist the user's preference across reloads. For accessibility, the toggle's screen reader announcement must make sense (e.g. "dark mode toggle on"). Since I want to display an SVG instead of a checkbox with text, I'll have to add focus and hover styling and a label that shows up on hover.
First, I need a Toggle class that creates an HTML element. Using the Custom Element API, I'll define
Using the class's constructor, I set the innerHTML of
Once the HTML is in place, I add a connectedCallback function to the class. This part of the custom elements API defines functions for use within the component and executes code when the component is inserted into the DOM.
// /components/toggle.js class Toggle extends HTMLElement { constructor() { super(); this.innerHTML = ` <label title="dark mode toggle"> <input type="checkbox" id="theme-toggle" class="theme-switch" /> <svg id="daisy">{SVG code removed for brevity}</svg> </label> ` this.setAttribute("class", "toggle-component"); } connectedCallback() { function switchTheme(e) { if (e.target.checked) { setTheme('dark'); return; } setTheme('light'); }; function setTheme(themeName) { localStorage.setItem('theme', themeName); document.documentElement.setAttribute('data-theme', themeName); }; function setCheckBox(toggleSwitch, theme) { toggleSwitch.checked = theme === 'dark' ? true : false; } function keepTheme() { const toggleSwitch = document.querySelector('#theme-toggle'); toggleSwitch.addEventListener('change', switchTheme, false); const theme = localStorage.getItem('theme'); if (theme) { setTheme(theme); setCheckBox(toggleSwitch, theme); return; }; const prefersLightTheme = window.matchMedia('(prefers-color-scheme: light)'); if (prefersLightTheme.matches) { setTheme('light'); return; }; setTheme('dark'); setCheckBox(toggleSwitch, 'dark'); }; document.addEventListener("DOMContentLoaded", keepTheme); } } customElements.define("toggle-component", Toggle);
Because
The rest of keepTheme is dedicated to choosing the right theme on load. First, it checks localStorage to see if the user's preference is already set. Next, it checks if prefers-color-scheme is set to 'light'. Finally, it defaults to dark mode. For both dark and light mode, I call setTheme. For dark mode, I also call setCheckbox. The checkbox mounts in an unchecked state. A screen reader will announce "dark mode" and whether the checkbox is checked. To get an announcement like "dark mode toggle checked" or "dark mode toggle on", I have to programmatically check the checkbox when I set the theme to 'dark' on load.
I chose to draw a fairly simple design so I could put my SVG code directly in the web component and programmatically change the fill color. This way, the background color of the daisy always matches the theme. Next, I use opacity: 0; to hide the checkbox and position it in the middle of the image. Finally, I add the hover and focus styles.
// /components/toggle.js class Toggle extends HTMLElement { constructor() { super(); this.innerHTML = ` <label title="dark mode toggle"> <input type="checkbox" id="theme-toggle" class="theme-switch" /> <svg id="daisy">{SVG code removed for brevity}</svg> </label> ` this.setAttribute("class", "toggle-component"); } connectedCallback() { function switchTheme(e) { if (e.target.checked) { setTheme('dark'); return; } setTheme('light'); }; function setTheme(themeName) { localStorage.setItem('theme', themeName); document.documentElement.setAttribute('data-theme', themeName); }; function setCheckBox(toggleSwitch, theme) { toggleSwitch.checked = theme === 'dark' ? true : false; } function keepTheme() { const toggleSwitch = document.querySelector('#theme-toggle'); toggleSwitch.addEventListener('change', switchTheme, false); const theme = localStorage.getItem('theme'); if (theme) { setTheme(theme); setCheckBox(toggleSwitch, theme); return; }; const prefersLightTheme = window.matchMedia('(prefers-color-scheme: light)'); if (prefersLightTheme.matches) { setTheme('light'); return; }; setTheme('dark'); setCheckBox(toggleSwitch, 'dark'); }; document.addEventListener("DOMContentLoaded", keepTheme); } } customElements.define("toggle-component", Toggle);
All I need to do is import my stylesheet and component script in the
of an HTML page. Then I can call/* /styles/styles.css */ [data-theme="light"] { --toggle-background: #242D54; } [data-theme="dark"] { --toggle-background: #282e53; } #daisy path { fill: var(--toggle-background); } .theme-switch { position: relative; bottom: 30px; left: 55px; width: 1em; height: 1em; opacity: 0; } .theme-switch:focus + #daisy path, .theme-switch:hover + #daisy path { fill: white; } .theme-switch:focus + #daisy { outline: 3px solid white; outline-offset: 5px; }
I had fun getting my dark mode toggle to work just as well in a web component as it does in React. You can see this live in my digital garden and the full code in the GitHub repo.
The above is the detailed content of Dark Mode Toggle in HTML Web Components. For more information, please follow other related articles on the PHP Chinese website!