Local Storage Head (Theme Switcher)

Persist theme and style preferences to localStorage and sync with document classes.

Table of contents

Usage

The LSH (Local Storage Head) component provides an easy way to manage theme switching and style preferences. It stores selections in localStorage under the key __Z_THEME__ and applies them as classes to the <html> element. Multiple instances automatically stay in sync.

To implement LSH, you’ll need to make some modifications to your HTML code to allow users to change their preferences.

1. Start by setting a default theme and mode in the <head> tag of your HTML by checking the user’s preference:

<script>
  const htmlElement = document.documentElement;

  const __Z_THEME__ = JSON.parse(localStorage.getItem("__Z_THEME__") || "{}");

  if (
    __Z_THEME__.mode === "dark" ||
    (!__Z_THEME__.mode &&
      window.matchMedia("(prefers-color-scheme: dark)").matches)
  ) {
    htmlElement.classList.add("dark");
  } else {
    htmlElement.classList.remove("dark");
  }

  /* below is just an example, feel free to implement your own */
  htmlElement.classList.add(__Z_THEME__.layout || "z-layout-small");
  htmlElement.classList.add(__Z_THEME__.ff || "z-ff-a");
</script>

This will first check if a user previously set the theme color preference manually using localStorage, and as a fallback, it will either set dark or light mode based on the browser’s color scheme preference.

Note You can replace z-[group]-[value] with anything you want as the default.

2. Ensure that your <body> tag includes the classes bg and color to apply the proper background and text colors that automatically adapt to the currently set theme.

<!doctype html>
<html lang="en">
  <head>
    <!-- ... -->
  </head>
  <body class="bg color" style="--bg: var(--z-bg); --color: var(--z-bg-f)">
    <!-- ... -->
  </body>
</html>

3. You can now use any instance of <z-lsh> component anywhere in your HTML.

Theme toggle

Enable toggle mode to create a button that switches between light and dark modes:

When toggle is enabled with group="mode", the button automatically switches between light and dark modes, ignoring the value attribute.

Configuration groups

The component supports multiple configuration groups beyond just light/dark mode:

Mode group (special behavior)

The mode group has special handling:

  • value="light" removes the dark class from <html>
  • value="dark" adds the dark class to <html>
<z-lsh group="mode" value="light">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

<z-lsh group="mode" value="dark">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

Custom groups

Other groups apply class names directly to the <html> element:

<!-- Color themes -->
<z-lsh group="color" value="z-theme-blue">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>
<z-lsh group="color" value="z-theme-red">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>
<z-lsh group="color" value="z-theme-green">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

<!-- Font sizes -->
<z-lsh group="font" value="z-font-small">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>
<z-lsh group="font" value="z-font-medium">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>
<z-lsh group="font" value="z-font-large">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

When switching within a group, the component automatically removes the previous class with the same prefix.

Prevent auto-update

By default, all instances sync when one changes. Use prevent-autoupdate to create standalone buttons:

<z-lsh group="mode" value="dark" prevent-autoupdate>
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

Programmatic control

Listen to events to respond to theme changes:

<z-lsh id="theme-toggle" toggle group="mode">
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

<script>
  const toggle = document.getElementById("theme-toggle");

  // Before change (cancelable)
  toggle.addEventListener("z-lsh:before-change", (e) => {
    console.log("About to change:", e.detail);
    // e.preventDefault(); // Cancel the change
  });

  // After change
  toggle.addEventListener("z-lsh:change", (e) => {
    console.log("Changed:", e.detail);
    // e.detail.group - The configuration group
    // e.detail.value - The new value
    // e.detail.previousValue - The old value
    // e.detail.config - Complete configuration object
  });
</script>

Local storage structure

The component stores configuration in localStorage under the key __Z_THEME__:

{
  "mode": "dark",
  "color": "z-theme-blue",
  "font": "z-font-medium"
}

Internationalization

The LSH component supports internationalization through multiple methods with the following priority order (highest to lowest):

  • Component-level i18n (via i18n attribute or script tag)
  • Global component-specific namespace (via <script id="z-i18n">)
  • Default values

Using the i18n attribute

<z-lsh
  toggle
  group="mode"
  i18n='{"aria-label": "Cambiar tema", "switch-to-dark": "Cambiar a modo oscuro", "switch-to-light": "Cambiar a modo claro"}'
>
</z-lsh>

Using a configuration script

<z-lsh toggle group="mode">
  <script type="application/json" data-fn="config">
    {
      "i18n": {
        "aria-label": "Thème bascule",
        "switch-to-dark": "Passer en mode sombre",
        "switch-to-light": "Passer en mode clair"
      }
    }
  </script>
  
  <template data-fn="template">🌓</template>
</z-lsh>

Available i18n options

KeyDefaultDescription
aria-labelToggle themeARIA label for the button
active-labelActiveLabel appended to ARIA when button is active
switch-to-darkSwitch to dark modeARIA description when switching to dark (toggle mode)
switch-to-lightSwitch to light modeARIA description when switching to light (toggle mode)

Custom classes

The LSH component supports custom CSS classes through the cls attribute.

Using simple string format

<z-lsh cls="my-theme-button" toggle group="mode">
  <template data-fn="template">
      <!-- -->
  </template>
</z-lsh>

Using JSON object format

<z-lsh
  cls='{"button": "z-button z-button-primary z-lsh"}'
  toggle
  group="mode"
>
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

Available cls target

TargetDescription
buttonThe button element

Custom inline styles

The LSH component supports custom inline styles through the stl attribute.

Example

<z-lsh
  stl='{"button": "padding: 0.5rem 1rem; border-radius: 8px;"}'
  toggle
  group="mode"
>
  <template data-fn="template">
    <!-- -->
  </template>
</z-lsh>

Attributes

NameTypeDefaultDescription
valueStringThe specific theme value to apply (e.g., “dark”, “z-theme-blue”)
groupStringConfiguration group (e.g., “mode”, “color”, “font”)
toggleBooleanfalseEnables toggle behavior for mode switching (ignores value attribute)
prevent-autoupdateBooleanfalsePrevents this instance from syncing with other instances
clsStringCustom CSS classes for the button
stlStringCustom inline styles for the button
i18nStringInternationalization strings as JSON object or via configuration script
force-prevent-rerenderBooleanfalsePrevents component rerendering (useful for HTMX or SPA scenarios)

Events

NameDescription
z-lsh:before-changeFired before theme change (cancelable). Event detail contains {group, value, previousValue, config}.
z-lsh:changeFired after theme change. Event detail contains {group, value, previousValue, config}.