lightdni-jssas-toggle
v1.1.1
Published
TypeScript utility package for applying and toggling CSS themes in website projects.
Readme
lightdni-jssas-toggle
TypeScript utility package for applying and toggling CSS themes in website projects.
Features
- Apply theme classes and attributes to the root element
- Set CSS variables dynamically
- Use a consolidated one-call
setThemeAPI to reduce integration code - Persist selected theme name to localStorage
- Persist selected theme name in cookies
- Toggle between light/dark theme names
- Add accessibility metadata (color-scheme and live announcements)
- Use dependency-safe behavior for environments where browser globals are not available
- Works in vanilla JS/TS, React, and Vue projects
Installation
npm install lightdni-jssas-toggleCore API
import {
applyTheme,
clearThemeVariables,
clearPersistedThemeNameCookie,
persistThemeNameInCookie,
persistThemeName,
readPersistedThemeNameFromCookie,
readPersistedThemeName,
setTheme,
toggleThemeName,
validateThemeFromHeadTitle
} from "lightdni-jssas-toggle";Accessibility Keystones
- Perceivable feedback: announce theme changes through an
aria-liveregion so assistive technologies report updates. - Understandable contrast intent: set
color-schemeto align browser controls and form widgets with the active theme. - Robust persistence behavior: keep theme preference stable across visits via localStorage/cookie options.
One-Call Integration (Primary)
Use setTheme when you want to apply theme styles, persist user choice, and apply accessibility metadata in one call.
import { setTheme } from "lightdni-jssas-toggle";
const themes = {
light: {
className: "theme-light",
dataTheme: "light",
variables: {
"--bg": "#ffffff",
"--text": "#111111"
}
},
dark: {
className: "theme-dark",
dataTheme: "dark",
variables: {
"--bg": "#101820",
"--text": "#f2f2f2"
}
}
} as const;
const liveRegion = document.getElementById("theme-live-region") as HTMLElement;
setTheme({
themeName: "dark",
themes,
previousClassNames: ["theme-light", "theme-dark"],
persistKey: "site-theme",
persistence: "both",
accessibility: {
setColorScheme: true,
announceTo: liveRegion,
announceTemplate: (theme) => `Theme changed to ${theme}`
}
});Vanilla Usage
import {
setTheme,
readPersistedThemeName,
toggleThemeName
} from "lightdni-jssas-toggle";
const themes = {
light: {
className: "theme-light",
dataTheme: "light",
variables: {
"--bg": "#ffffff",
"--text": "#111111"
}
},
dark: {
className: "theme-dark",
dataTheme: "dark",
variables: {
"--bg": "#101820",
"--text": "#f2f2f2"
}
}
} as const;
const stored = readPersistedThemeName() ?? "light";
let currentTheme = stored === "dark" ? "dark" : "light";
setTheme({
themeName: currentTheme,
themes,
previousClassNames: ["theme-light", "theme-dark"],
persistence: "both"
});
document.getElementById("theme-toggle")?.addEventListener("click", () => {
currentTheme = toggleThemeName(currentTheme, "light", "dark") as "light" | "dark";
setTheme({
themeName: currentTheme,
themes,
previousClassNames: ["theme-light", "theme-dark"],
persistence: "both"
});
});React Usage
import { useEffect, useMemo, useState } from "react";
import {
setTheme,
readPersistedThemeName,
toggleThemeName
} from "lightdni-jssas-toggle";
type ThemeName = "light" | "dark";
const themeMap = {
light: {
className: "theme-light",
dataTheme: "light",
variables: { "--bg": "#ffffff", "--text": "#111111" }
},
dark: {
className: "theme-dark",
dataTheme: "dark",
variables: { "--bg": "#111827", "--text": "#f9fafb" }
}
} as const;
export function ThemeToggleButton() {
const initialTheme = (readPersistedThemeName() as ThemeName | null) ?? "light";
const [theme, setTheme] = useState<ThemeName>(initialTheme);
const currentThemeDefinition = useMemo(() => themeMap[theme], [theme]);
useEffect(() => {
setTheme({
themeName: theme,
themes: themeMap,
previousClassNames: ["theme-light", "theme-dark"],
persistence: "localStorage"
});
}, [currentThemeDefinition, theme]);
return (
<button
type="button"
onClick={() => setTheme((prev) => toggleThemeName(prev, "light", "dark") as ThemeName)}
>
Toggle Theme
</button>
);
}Vue Usage
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import {
setTheme,
readPersistedThemeName,
toggleThemeName
} from "lightdni-jssas-toggle";
type ThemeName = "light" | "dark";
const themeName = ref<ThemeName>((readPersistedThemeName() as ThemeName | null) ?? "light");
const themeDefinition = computed(() => {
if (themeName.value === "dark") {
return {
className: "theme-dark",
dataTheme: "dark",
variables: {
"--bg": "#0b1020",
"--text": "#f8fafc"
}
};
}
return {
className: "theme-light",
dataTheme: "light",
variables: {
"--bg": "#ffffff",
"--text": "#0f172a"
}
};
});
watch(
themeDefinition,
() => {
setTheme({
themeName: themeName.value,
themes: {
light: {
className: "theme-light",
dataTheme: "light",
variables: {
"--bg": "#ffffff",
"--text": "#0f172a"
}
},
dark: {
className: "theme-dark",
dataTheme: "dark",
variables: {
"--bg": "#0b1020",
"--text": "#f8fafc"
}
}
},
previousClassNames: ["theme-light", "theme-dark"],
persistence: "both"
});
},
{ immediate: true }
);
function onToggleTheme(): void {
themeName.value = toggleThemeName(themeName.value, "light", "dark") as ThemeName;
}
</script>
<template>
<button type="button" @click="onToggleTheme">Toggle Theme</button>
</template>Development
npm install
npm run lint
npm run typecheck
npm run test
npm run buildTests run on Node's built-in test runner (node:test) via tsx, with jsdom providing the DOM environment. No Vitest/Vite dependency is required.
Publish Checklist
- Ensure all checks pass:
npm run lintnpm run typechecknpm run testnpm run build
- Verify npm package contents:
npm run pack:check
- Publish to npm:
npm publish --access public
License
MIT
