toggle-theme-circular
v1.1.0
Published
Framework-agnostic TypeScript theme switcher with circular View Transition reveals.
Maintainers
Readme
theme-toggle-circular
Framework-agnostic theme switching with a circular reveal animation driven by the View Transition API.
Description
theme-toggle-circular solves a common UI problem: switching between light and dark themes without a plain crossfade or a layout jump. It exists for applications that want a small, framework-neutral utility with a polished reveal effect that starts from the actual button click position.
Internally, the library updates the theme class, persists the choice, and uses the View Transition API plus a clip-path animation to reveal the new theme from the interaction point. When the API is unavailable, it falls back cleanly to a normal theme switch.
Features
- Framework agnostic
- TypeScript support
- Zero runtime dependencies
- Tailwind compatible
- Circular reveal animation
- Dark and light theme persistence
- System preference support
- Graceful fallback when View Transition API is unavailable
Installation
npm install theme-toggle-circularQuick Start
import { createThemeToggle } from "theme-toggle-circular";
const theme = createThemeToggle();
button.addEventListener("click", (event) => {
theme.toggle(event);
});CSS Setup
The circular reveal relies on View Transition pseudo-elements. Import the package stylesheet once in your app:
import "theme-toggle-circular/style.css";If you prefer to inline the required rules manually, this is the minimum setup:
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}API Documentation
createThemeToggle(options?)
Creates a theme controller with persistence and circular transitions.
ThemeToggle
toggle(origin?)toggles between light and dark themesset(theme, origin?)sets a specific themecurrentreturns the active themedestroy()removes internal listeners
Options
The library accepts both nested options and top-level aliases for convenience.
darkClass: class name applied to the root element when dark mode is activestorageKey: storage key used to persist the selected themeduration: animation duration in millisecondseasing: CSS easing function used by the reveal animationfollowSystemOnStart: whether the initial theme should follow the system preference when nothing is stored
Nested forms are also supported:
theme.darkClasstheme.followSystemOnStartstorage.keyanimation.durationanimation.easing
Framework Examples
Vanilla JavaScript
import "theme-toggle-circular/style.css";
import { createThemeToggle } from "theme-toggle-circular";
const theme = createThemeToggle();
const button = document.querySelector<HTMLButtonElement>("#theme-btn");
button?.addEventListener("click", (event) => {
theme.toggle(event);
});React
import { useEffect, useRef } from "react";
import { createThemeToggle } from "theme-toggle-circular";
export function ThemeButton() {
const theme = useRef(createThemeToggle());
useEffect(() => () => theme.current.destroy(), []);
return <button onClick={(event) => theme.current.toggle(event.nativeEvent)}>Theme</button>;
}Vue 3
<script setup lang="ts">
import { onBeforeUnmount } from "vue";
import { createThemeToggle } from "theme-toggle-circular";
const theme = createThemeToggle();
onBeforeUnmount(() => theme.destroy());
</script>
<template>
<button @click="(event) => theme.toggle(event)">Theme</button>
</template>Svelte
<script lang="ts">
import { onDestroy } from "svelte";
import { createThemeToggle } from "theme-toggle-circular";
const theme = createThemeToggle();
onDestroy(() => theme.destroy());
</script>
<button on:click={(event) => theme.toggle(event)}>Theme</button>Browser Support
The circular reveal requires the View Transition API, which is currently supported in Chromium-based browsers. When the API is not available, the library still switches themes and persists the result, but without the animated reveal.
Architecture
browser/contains DOM and browser capability helperscore/contains defaults, option resolution, and state managementtypes/defines the public TypeScript APIutils/contains shared math and utility helpers
Contributing
Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.
Local workflow:
npm ci
npm run typecheck
npm run lint
npm run test
npm run buildLicense
MIT
