Dark Mode Switcher for Shopify
Overview
A dark mode toggle for Online Store 2.0 and vintage themes, built as two Liquid snippets plus a static stylesheet and script. A blocking inline script in <head> resolves the theme from localStorage, prefers-color-scheme and a merchant default, and writes data-theme plus color-scheme on <html> before the browser paints its first frame; the toggle keeps a fixed box in every state so switching cannot reflow the header. It ships a semantic CSS custom property layer wired to theme settings, cross-tab sync via the storage event, reduced-motion handling, and re-sync on the Shopify theme editor's section events. It does not automatically restyle an existing theme - the buyer has to point their own CSS at the tokens. 1.1.0 adds a settings/schema/README cross-checker, light/dark screenshots, and `npm run measure`: a dependency-free headless-Chrome tool that reproduces the pre-paint and CLS measurements on the buyer's own machine, against the bundled harness or their own storefront, including a control mode that makes the same measurement fail on purpose.
Source preview
2. the operating system, when we are allowed to follow it AND it told us
3. the merchant's configured default
Returns { theme, preference, source }. `theme` is always 'light' or 'dark'. */
function resolveTheme(input) {
var opts = input || {};
var defaultTheme = normaliseTheme(opts.defaultTheme) || LIGHT;
var followSystem = opts.followSystem !== false;
var systemPrefersDark =
typeof opts.systemPrefersDark === 'boolean' ? opts.systemPrefersDark : null;
var stored = normalisePreference(opts.storedPreference);
if (stored === LIGHT || stored === DARK) {
return { theme: stored, preference: stored, source: 'stored' };
}
var choseSystem = stored === SYSTEM;
if ((choseSystem || followSystem) && systemPrefersDark !== null) {
return {
theme: systemPrefersDark ? DARK : LIGHT,
preference: SYSTEM,
source: 'system'
};
}
return {
theme: defaultTheme,
preference: choseSystem ? SYSTEM : defaultTheme,
source: 'default'
};
}Excludes tax, added at checkout where it applies.