Founding price: $35, then $99 after 23:59 UTC on 4 November, then $99
Get ProRun a theme change inside a View Transition with a circular reveal, falling back to an instant change when motion is reduced or unsupported.
Derived from this item’s props table, because it declares no controls of its own. This item has no standalone playground, so changes update the code, the share link and the AI prompt.
Use it for the theme or mode switch, or for applying a theme from a picker. The new look grows from where the person clicked (a circular reveal) or cross-fades, using the View Transitions API. Where the browser lacks it, or the person asked for reduced motion, the change is applied at once with no animation.
Do not use it for changes that are already animated by the components themselves, and do not pass an update that waits for data: it must change the DOM synchronously.
import { useThemeTransition } from "@/hooks/use-theme-transition"const { run, isSupported } = useThemeTransition({ duration: 500 })
<button onClick={(event) => run(() => setMode(next), { origin: event })}>
Toggle theme
</button>useThemeTransition(defaults?): { run, isSupported, isTransitioning }
| Option | Type | Default | Description |
|---|---|---|---|
type | "circle" | "fade" | "circle" | Circular reveal from origin, or a cross-fade. |
duration | number | 500 | Milliseconds. |
easing | string | "ease-in-out" | CSS easing. |
origin (per call) | { x, y }, a pointer event, or an element | centre of the window | Where the circle starts. |
run(update, options?) returns a promise that resolves to true when it animated and false when it applied the change without animation. isSupported is false on the server and until the first effect, so render the same markup for both.
prefers-reduced-motion: reduce turns the animation off: the update is applied at once. The hook does not move focus and adds no markup; keep the control that triggers it a real button with an accessible name, and announce the new mode in your own live region if the label does not change.
The hook ships with a test (use-theme-transition.test.ts). It covers the fallback when View Transitions are missing, the reduced-motion fallback, the circular reveal (clip-path keyframes and the pseudo-element), a skipped transition, cleanup of the injected style, and the cross-fade.