Theme Multi Switch Web Component

Super Small! 4.04 KiB / gzip: 1.75 KiB

Github: colinaut/theme-multi-switch

NPM: @colinaut/theme-multi-switch




Modified css variables, css styling of parts, and added svgs to slots

Different Themes

Two Switch

Two Switch

Layout "top" with increased knob width

Four Switch

Layout "bottom" with increased knob width

I created this three way switch for setting theme as I couldn't find what I was looking for — most are two way switches and I wanted to allow for auto. So I built a three way switch which defaults to "auto" (for browser prefers-color-scheme) and allows "light" or "dark" for overriding prefers-color-scheme. I quickly realized that I could just as easily make it work with multiple themes!

When switch is triggered it:

You can also trigger the switch externally by either changing the "theme" prop or dispatching a "theme-switch" event with the theme in the detail.


Add the theme-multi-switch.js script to your project. Then add the component <theme-switch></theme-switch> to your html.

You can do this via CDN:

<script src=""></script>

Or you can pull it into your project via npm:

npm i @colinaut/theme-multi-switch

For best results, add this to your <head> so that it is render blocking. This avoids Flash of inAccurate coloR Theme (FART).


Sizing uses em so it can be resized by changing the css font-size. Base color for text, knob, and track border uses currentColor so it will update if you change the body text color.

The layout and knob-width properties

Further restyling is possible via slots, parts, and css variables. Properties allows changing defaults and values for changing meta theme-color.

Default Slots

  • light
  • auto
  • dark

Slots are dynamically named after the theme names.

Default Parts

  • light
  • auto
  • dark
  • track
  • knob

Label Parts are dynamically named after the theme names.

CSS Color Variables

  • --theme-switch-knob background: var(--theme-switch-knob, currentColor);
  • --theme-switch-track background: var(--theme-switch-track, #88888822);
  • --theme-switch-track-border border: 0.1em solid var(--theme-switch-border, currentColor);
  • --theme-switch-highlight color: var(--theme-switch-highlight, inherit);
  • --theme-switch-knob-width width: calc(var(--theme-switch-knob-width, 1) * 1em);


  • themes = "light,auto,dark"
  • theme = defaults to themes[1]
  • meta-colors = ""
  • layout = "around top"

themes and meta-colors accepts either a comma separated string or a stringified JSON array

layout can be either "around top", "around bottom", or just "top" or "bottom"

Example Auto/Light/Dark CSS

/* Values for light and dark */

:root {
    --header-light: rgb(95, 0, 0);
    --body-light: rgb(45, 45, 65);
    --bg-light: rgb(225, 225, 225);
    --track-light: rgb(205 195 165 /0.8);
    --highlight-light: rgb(155, 50, 0);

    --header-dark: rgb(250, 180, 120);
    --body-dark: rgb(225, 225, 225);
    --bg-dark: rgb(45, 45, 65);
    --track-dark: rgb(105 85 55 /0.6);
    --highlight-dark: rgb(225, 120, 100);

/* Automatic Light Mode; Light Mode Override */

:root[data-theme="light"] {
    --header: var(--header-light);
    --body: var(--body-light);
    --bg: var(--bg-light);
    --track: var(--track-light);
    --highlight: var(--highlight-light);

/* Dark Mode Override */

:root[data-theme="dark"] {
    --header: var(--header-dark);
    --body: var(--body-dark);
    --bg: var(--bg-dark);
    --track: var(--track-dark);
    --highlight: var(--highlight-dark);

/* Automatic Dark Mode */

@media (prefers-color-scheme: dark) {
    :root {
        --header: var(--header-dark);
        --body: var(--body-dark);
        --bg: var(--bg-dark);
        --track: var(--track-dark);
        --highlight: var(--highlight-dark);