Three states, not two
Light, dark and system — with the choice kept separate from what it resolves to, which a two-state switch cannot do.
<div class="demo demo--wide">
<div class="panel" id="panel">
<div class="panel-head">
<strong>A page</strong>
<div id="theme"></div>
</div>
<p class="panel-body">This panel follows the toggle. So do the controls below — that is
<code>color-scheme</code> doing its work, not CSS.</p>
<p class="demo-row">
<input class="demo-input" type="date" aria-label="A date">
<select class="demo-input" aria-label="A menu"><option>A native menu</option></select>
</p>
</div>
<div class="demo-row">
<div id="button"></div>
<span class="demo-hint">The same controller, as a cycling button.</span>
</div>
<dl class="demo-kv" id="out"></dl>
</div>
import { createTheme, createThemeToggle } from 'https://devix.pk/cdn/oss/theme-toggle@1.0.0/index.js';
const out = document.getElementById('out');
const panel = document.getElementById('panel');
// One controller, two controls, scoped to this panel rather than the whole page.
const theme = createTheme({
element: panel,
attribute: ['class', 'data-theme'],
storageKey: 'devix.demo.theme',
});
createThemeToggle(document.getElementById('theme'), { theme, labels: true });
createThemeToggle(document.getElementById('button'), { theme, variant: 'button' });
const show = () => {
out.innerHTML = `
<div><dt>chosen</dt><dd>${theme.get()}</dd></div>
<div><dt>resolved</dt><dd>${theme.resolved()}</dd></div>
<div><dt>your system says</dt><dd>${theme.system()}</dd></div>
<div><dt>color-scheme</dt><dd>${panel.style.colorScheme || '—'}</dd></div>`;
};
theme.subscribe(show);
show();
@import url('https://devix.pk/cdn/oss/theme-toggle@1.0.0/theme-toggle.min.css');
.panel {
--bg: #ffffff;
--fg: #18181b;
--line: #e4e4e7;
padding: 14px 16px;
border: 1px solid var(--line);
border-radius: 12px;
background: var(--bg);
color: var(--fg);
transition: background .2s, color .2s;
}
.panel.dark {
--bg: #101014;
--fg: #ededf0;
--line: #2c2c33;
}
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.panel-body { margin: 10px 0; font-size: 13px; }
.panel .demo-row { margin: 0; }