npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@supercat1337/color-scheme

v1.0.4

Published

Browser-only color scheme manager for Bootstrap 5 with dark/light mode auto-detection, localStorage persistence, and zero config — no init functions needed.

Downloads

295

Readme

@supercat1337/color-scheme

A tiny, fast, and easy-to-use color scheme and color theme management system for JavaScript applications that works with Bootstrap 5 and supports dark and light themes.

Browser‑only – This module is designed exclusively for the browser. It relies on DOM APIs (window, document, localStorage, sessionStorage, matchMedia). Importing it in a server environment (Node.js, SSR) will throw an explicit error. For SSR frameworks, use dynamic imports on the client side.

Overview

The module gives you a simple way to manage color schemes in your application. It reads the user's system preference, allows users to override it, and automatically applies the corresponding theme to the DOM. The module works seamlessly with Bootstrap 5 via the data-bs-theme attribute.

Terminology: Scheme vs Theme

  • Color Scheme (scheme) – Represents the user’s or system’s preference for a light or dark appearance. Possible values: "dark", "light", or "auto" (for preferred scheme). Schemes are stored and managed by *SchemeStorage classes.

  • Color Theme (theme) – Represents a concrete CSS theme name applied to the DOM via the data-bs-theme attribute. The theme is a string (e.g., "dark", "light", "custom-dark"). It determines which set of CSS variables or Bootstrap styles are active.

The CurrentSchemeStorage resolves the current scheme (from preferred/system) and then maps it to a theme name using getDefaultTheme(), which returns darkThemeName or lightThemeName. This separation allows you to:

  • Let users choose "auto" without worrying about theme names.
  • Use any custom theme name (e.g., "dark-blue") while keeping scheme logic unchanged.

Storage Architecture – How it works

The module uses three independent storage classes that work together:

  • SystemSchemeStorage – reads the OS/browser preference (prefers-color-scheme) and listens for changes.
  • PreferredSchemeStorage – stores the user's explicit choice ("dark", "light", or "auto") in localStorage and synchronises across tabs.
  • CurrentSchemeStorage – resolves the actual active scheme by combining:
    1. A manually overridden value stored in sessionStorage (if any).
    2. Otherwise, the preferred scheme (if not "auto").
    3. Otherwise, the system scheme.

Resolution rule:

sessionStorage override → preferred (non-auto) → system → "light" (fallback)

Important: CurrentSchemeStorage automatically subscribes to changes in both SystemSchemeStorage and PreferredSchemeStorage. Whenever they change, the current scheme is re‑evaluated and, if changed, emits a current-scheme-change event. This ensures "auto" mode works correctly without external glue code.

To apply a theme (e.g., Bootstrap's data-bs-theme), subscribe to currentSchemeStorage.onSchemeChange() and call applyColorTheme(currentSchemeStorage.getDefaultTheme()).

Installation

npm install @supercat1337/color-scheme

Usage

Quick start (recommended)

Import the ready‑to‑use global singletons. No initialisation function needed – the module automatically sets up everything when imported in a browser.

import {
    currentSchemeStorage,
    preferredSchemeStorage,
    systemSchemeStorage,
    applyColorTheme,
} from '@supercat1337/color-scheme';

// The current scheme is already applied to the document (data-bs-theme attribute).
// You can read it:
console.log(`Current scheme: ${currentSchemeStorage.scheme}`); // "dark" or "light"

// Listen for changes (e.g., to update a toggle switch)
currentSchemeStorage.onSchemeChange(scheme => {
    console.log(`Scheme changed to: ${scheme}`);
    // update your UI if needed
});

// Toggle dark/light mode with a switch
const switcher = document.querySelector('#darkmode-switch');
switcher.checked = currentSchemeStorage.scheme === 'dark';

switcher.addEventListener('change', () => {
    const newScheme = switcher.checked ? 'dark' : 'light';
    currentSchemeStorage.scheme = newScheme; // changes the active scheme
    preferredSchemeStorage.scheme = newScheme; // remember user's choice across sessions
});

// Get system preference
console.log(`System prefers: ${systemSchemeStorage.scheme}`);

Custom theme names

If you need theme names other than the default "dark" and "light" (for example, "dark-blue", "light-gray"), you cannot use the global singletons – they are pre‑configured with the defaults. Instead, create your own instances:

import {
    SystemSchemeStorage,
    PreferredSchemeStorage,
    CurrentSchemeStorage,
    applyColorTheme,
    addMetaThemeColor,
} from '@supercat1337/color-scheme';

const system = new SystemSchemeStorage();
const preferred = new PreferredSchemeStorage();
const current = new CurrentSchemeStorage(system, preferred, {
    darkThemeName: 'dark-blue',
    lightThemeName: 'light-gray',
});

// Add meta tags manually (optional)
addMetaThemeColor('#FFFFFF', '#212529');

// Apply theme on changes
current.onSchemeChange(() => {
    applyColorTheme(current.getDefaultTheme());
});

// Initial application
applyColorTheme(current.getDefaultTheme());

// Later, you can destroy the instances if needed:
// system.destroy();
// preferred.destroy();
// current.destroy();

Note: The exported global singletons (systemSchemeStorage, preferredSchemeStorage, currentSchemeStorage) are managed automatically. Do not call destroy() on them.

API Reference

Global singletons (available immediately on import)

| Singleton | Type | Description | | ------------------------ | ------------------------ | ---------------------------------------- | | systemSchemeStorage | SystemSchemeStorage | System (OS) preference | | preferredSchemeStorage | PreferredSchemeStorage | User preference (stored in localStorage) | | currentSchemeStorage | CurrentSchemeStorage | Resolved active scheme |

SystemSchemeStorage

  • get scheme(): "dark"|"light" – current system scheme.
  • onSchemeChange(callback: (scheme) => void): () => void – subscribe to changes.
  • destroy(): void – remove internal listeners (only needed for manual instances).

PreferredSchemeStorage

  • get scheme(): "dark"|"light"|"auto"
  • set scheme(value) – update and persist preference.
  • onSchemeChange(callback): () => void
  • destroy(): void

CurrentSchemeStorage

  • darkThemeName: string – theme name used for dark mode.
  • lightThemeName: string – theme name used for light mode.
  • get scheme(): "dark"|"light"
  • set scheme(value: "dark"|"light"|"auto") – sets the current scheme. If "auto", removes any session override and re‑evaluates from preferred/system.
  • getDefaultTheme(): string – returns darkThemeName or lightThemeName based on current scheme.
  • onSchemeChange(callback): () => void
  • destroy(): void

Utility functions

  • applyColorTheme(theme: string): void – sets data-bs-theme attribute on <html>.
  • applyColorThemeToElement(element: HTMLElement, theme: string): void – sets data-bs-theme on a specific element.
  • addMetaThemeColor(lightColor?: string, darkColor?: string): void – adds theme-color meta tags with media conditions.
  • getSystemPreferredColorScheme(): "dark"|"light" – returns current system scheme (read‑only).
  • onSystemColorSchemeChange(callback): () => void – low‑level subscription to system changes.

Important notes

  • Browser only – The module throws an error when imported in Node.js or any environment without window/document.
  • No initialisation required – As soon as you import the module in a browser, it automatically:
    • Adds the global style :root { color-scheme: light dark; }.
    • Adds theme-color meta tags (light: #FFFFFF, dark: #212529).
    • Creates the global singletons and starts listening to system/preferred changes.
    • Applies the initial theme to document.documentElement.
  • SSR workaround – If you use Next.js, Nuxt, SvelteKit, or any SSR framework, you must import the module only on the client side:
    // In a client‑side hook (e.g., useEffect, onMounted)
    useEffect(() => {
        import('@supercat1337/color-scheme').then(({ currentSchemeStorage }) => {
            // use currentSchemeStorage
        });
    }, []);
  • Persisting user choice – Always set preferredSchemeStorage.scheme together with currentSchemeStorage.scheme if you want the choice to survive page reloads.
  • "auto" behaviour – Setting currentSchemeStorage.scheme = "auto" removes the sessionStorage override and re‑enables automatic following of preferred/system changes.

Browser support

  • Modern browsers with ES2022+ (private class fields, CSSStyleSheet, matchMedia, localStorage/sessionStorage).
  • Works with Bootstrap 5 (via data-bs-theme).

License

MIT © Albert Bazaleev aka supercat1337