Animated Theme Toggler
svelte-animations/animated-theme-togglerFreeBlock
A smooth animated theme toggler that uses the View Transition API to create a circular reveal effect when switching between light and dark themes.
Install it
npx shadcn@latest add https://sv-animations.vercel.app/r/animated-theme-toggler.jsonSource
1<script lang="ts">2 import { onMount } from "svelte";3 import { Moon, Sun } from "@lucide/svelte";4 import { cn } from "$UTILS$";56 interface AnimatedThemeTogglerProps {7 class?: string;8 duration?: number;9 }1011 let { class: className, duration = 400, ...props }: AnimatedThemeTogglerProps = $props();1213 let isDark = $state(false);14 let buttonRef: HTMLButtonElement | null = $state(null);1516 onMount(() => {17 const updateTheme = () => {18 isDark = document.documentElement.classList.contains("dark");19 };2021 updateTheme();2223 const observer = new MutationObserver(updateTheme);24 observer.observe(document.documentElement, {25 attributes: true,26 attributeFilter: ["class"],27 });2829 return () => observer.disconnect();30 });3132 const toggleTheme = async () => {33 if (!buttonRef) return;3435 // Check if View Transition API is supported36 if (!document.startViewTransition) {37 // Fallback for browsers that don't support View Transition API38 const newTheme = !isDark;39 isDark = newTheme;40 document.documentElement.classList.toggle("dark");41 localStorage.setItem("theme", newTheme ? "dark" : "light");42 return;43 }4445 await document.startViewTransition(() => {46 const newTheme = !isDark;47 isDark = newTheme;48 document.documentElement.classList.toggle("dark");49 localStorage.setItem("theme", newTheme ? "dark" : "light");50 }).ready;5152 const { top, left, width, height } = buttonRef.getBoundingClientRect();53 const x = left + width / 2;54 const y = top + height / 2;55 const maxRadius = Math.hypot(56 Math.max(left, window.innerWidth - left),57 Math.max(top, window.innerHeight - top)58 );5960 document.documentElement.animate(61 {62 clipPath: [63 `circle(0px at ${x}px ${y}px)`,64 `circle(${maxRadius}px at ${x}px ${y}px)`,65 ],66 },67 {68 duration,69 easing: "ease-in-out",70 pseudoElement: "::view-transition-new(root)",71 }72 );73 };74</script>7576<button bind:this={buttonRef} onclick={toggleTheme} class={cn(className)} {...props}>77 {#if isDark}78 <Sun />79 {:else}80 <Moon />81 {/if}82 <span class="sr-only">Toggle theme</span>83</button>
Files it writes
More from Svelte Animations
All 66 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Beamanimated-beam | Svelte Animations | Blocks | Free | 1 dep · 6 files | |
| Animated Circular Progress Baranimated-circular-progress-bar | Svelte Animations | Blocks | Free | no deps · 2 files | |
| Animated Gradient Textanimated-gradient-text | Svelte Animations | Blocks | Free | no deps · 2 files | |
| Animated Grid Patternanimated-grid-pattern | Svelte Animations | Blocks | Free | 1 dep · 2 files | |
| Animated Listanimated-list | Svelte Animations | Blocks | Free | 1 dep · 2 files | |
| Animated Shiny Textanimated-shiny-text | Svelte Animations | Blocks | Free | no deps | |
| Arc Timelinearc-timeline | Svelte Animations | Blocks | Free | no deps · 3 files | |
| Aurora Textaurora-text | Svelte Animations | Blocks | Free | no deps · 2 files |
