@pshah-lab/themeswitcher
v0.1.4
Published
Light, dark, and system theme manager with SSR-safe no-flash support
Maintainers
Readme
@pshah-lab/themeswitcher
A lightweight, framework-agnostic theme manager for light, dark, and system modes — with SSR-safe no-flash support.
Designed to be:
- Minimal
- Predictable
- Copy-paste friendly
- Framework independent
Features
- Light / Dark / System theme support
- Prevents flash of incorrect theme (FOUC)
- SSR-safe (works before JS bundle loads)
- No dependencies
- Fully typed (TypeScript)
- Works with plain JS, React, Vue, or any framework
Installation
npm install @pshah-lab/themeswitcherCore Usage (Framework-agnostic)
import { createThemeManager } from "@pshah-lab/themeswitcher";
const theme = createThemeManager();
theme.set("dark"); // "light" | "dark" | "system"
theme.toggle(); // toggle light ↔ dark
theme.get(); // resolved theme: "light" | "dark"
theme.getMode(); // selected modeThe theme is applied to the document using a data attribute:
<html data-theme="dark">Style your app using this attribute:
[data-theme="dark"] {
background: #000;
color: #fff;
}React Usage
Create the hook once at module scope.
// theme.ts
import { createUseTheme } from "@pshah-lab/themeswitcher";
export const useTheme = createUseTheme();Use it anywhere in your app:
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
Current theme: {theme}
</button>
);
}⚠️ Do not call createUseTheme() inside components.
It must be created once and reused.
Prevent Theme Flash (Recommended)
When using light/dark themes, browsers may briefly render the page in the default theme before JavaScript loads. This causes a visible flash of incorrect theme.
To prevent this, add the following script inline in your HTML <head>, before any CSS is loaded.
Why this is needed
- Runs before first paint
- Applies the correct theme synchronously
- Works before your JavaScript bundle loads
- Required for SSR
- Strongly recommended for all setups
Add this to <head>
<script>
(function () {
try {
var key = "theme-mode";
var attribute = "data-theme";
var stored = localStorage.getItem(key);
var mode =
stored === "light" || stored === "dark" || stored === "system"
? stored
: "system";
var isDark =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
var theme =
mode === "system"
? isDark
? "dark"
: "light"
: mode;
document.documentElement.setAttribute(attribute, theme);
} catch (e) {
// fail silently
}
})();
</script>Place it before your CSS:
<head>
<!-- Prevent theme flash -->
<script>/* pasted theme script */</script>
<link rel="stylesheet" href="styles.css" />
</head>Important Notes
- Do not import this script from the package
- Do not bundle it
- Copy-paste is intentional and required for correct timing
- The script logic matches the internal theme manager
Configuration
createThemeManager({
defaultMode: "system", // default
storageKey: "theme-mode", // localStorage key
attribute: "data-theme", // HTML attribute
});API Reference
set(mode)
Set the theme mode.
theme.set("dark");toggle()
Toggle between light and dark.
theme.toggle();get()
Get the resolved theme.
theme.get(); // "light" | "dark"getMode()
Get the selected mode.
theme.getMode(); // "light" | "dark" | "system"Design Philosophy
- Explicit over magical
- Copy-paste over runtime hacks
- No global side effects
- No framework lock-in
- Predictable behavior
License
MIT
