usePrefersReducedMotion
sora-ui/hooks-use-prefers-reduced-motionFreeHook
A hook that tracks the OS-level Reduced Motion setting live, so GSAP-driven primitives can skip or shortcut their animations.
Install it
npx shadcn@latest add https://ui.soralabs.io.vn/r/hooks-use-prefers-reduced-motion.jsonSource
1"use client";23import { useEffect, useLayoutEffect, useState } from "react";45const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";67// useLayoutEffect is a no-op (with a console warning) during SSR — fall back8// to useEffect there since there's no window/matchMedia to read anyway.9const useIsomorphicLayoutEffect =10 typeof window === "undefined" ? useEffect : useLayoutEffect;1112/**13 * Tracks the OS-level Reduced Motion setting, live. Unlike a one-time14 * `matchMedia(...).matches` check, this updates if the user toggles the15 * setting while the page is open (no reload needed).16 *17 * Defaults to `true`, not `false`. A consumer that mounts a GSAP18 * ScrollTrigger off this value reads it during its *first* render's effects19 * no matter which effect phase either hook uses — React doesn't re-render20 * mid-flush just because this hook's own effect called setState. Defaulting21 * to `false` meant every mount briefly created a real, pinned ScrollTrigger22 * before correcting a render later; anyone scrolling in that window saw the23 * full animation despite reduced motion being on. Defaulting to `true`24 * flips which side gets the one-frame guess: a non-reduced-motion user25 * waits one imperceptible frame for the animation to start, instead of a26 * reduced-motion user getting a live trigger they were never supposed to.27 */28export function usePrefersReducedMotion(): boolean {29 const [prefersReducedMotion, setPrefersReducedMotion] = useState(true);3031 useIsomorphicLayoutEffect(() => {32 const media = window.matchMedia(REDUCED_MOTION_QUERY);33 const update = () => {34 setPrefersReducedMotion(media.matches);35 };36 update();37 media.addEventListener("change", update);38 return () => {39 media.removeEventListener("change", update);40 };41 }, []);4243 return prefersReducedMotion;44}
Files it writes
More from Sora UI
All 97 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| useAutoHeighthooks-use-auto-height | Sora UI | Hooks | Free | no deps | |
| useControlledStatehooks-use-controlled-state | Sora UI | Hooks | Free | no deps | |
| useIsInViewhooks-use-is-in-view | Sora UI | Hooks | Free | 1 dep |
