Skip to content

Instantly share code, notes, and snippets.

@omer-os
Created December 29, 2025 19:03
Show Gist options
  • Select an option

  • Save omer-os/5b7d454b27d082abfd0cae7028b19874 to your computer and use it in GitHub Desktop.

Select an option

Save omer-os/5b7d454b27d082abfd0cae7028b19874 to your computer and use it in GitHub Desktop.
Circle Theme Switch Animation
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-new(root) {
z-index: 9999;
}
import { useTheme } from "next-themes"
export const ThemeToggle = () => {
const { theme, setTheme } = useTheme()
const toggleTheme = async (e: React.MouseEvent) => {
const newTheme = theme === "dark" ? "light" : "dark"
if (!document.startViewTransition) {
setTheme(newTheme)
return
}
const x = e.clientX
const y = e.clientY
const endRadius = Math.hypot(
Math.max(x, window.innerWidth - x),
Math.max(y, window.innerHeight - y)
)
const transition = document.startViewTransition(() => {
setTheme(newTheme)
})
await transition.ready
document.documentElement.animate(
{
clipPath: [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
],
},
{
duration: 500,
easing: "ease-in-out",
pseudoElement: "::view-transition-new(root)",
}
)
}
return (
<button onClick={toggleTheme}>Toggle</button>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment