Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | import { useEffect, useState } from 'react'; /** * Get initial reduced motion preference (SSR-safe) */ function getInitialValue(): boolean { if (typeof window === 'undefined') return false; return window.matchMedia('(prefers-reduced-motion: reduce)').matches; } /** * Hook to detect if the user prefers reduced motion. * Respects the user's system preference for reduced motion accessibility. * * @returns boolean indicating if reduced motion is preferred * * @example * ```tsx * function AnimatedComponent() { * const prefersReducedMotion = usePrefersReducedMotion(); * * return ( * <motion.div * animate={prefersReducedMotion ? {} : { scale: 1.1 }} * transition={prefersReducedMotion ? { duration: 0 } : { duration: 0.3 }} * > * Content * </motion.div> * ); * } * ``` * * @example * ```tsx * // Conditionally apply animations * function FadeIn({ children }) { * const prefersReducedMotion = usePrefersReducedMotion(); * * if (prefersReducedMotion) { * return <div>{children}</div>; * } * * return ( * <div className="animate-fadeIn"> * {children} * </div> * ); * } * ``` */ export function usePrefersReducedMotion(): boolean { // Initialize with the actual value (SSR-safe via function) const [prefersReducedMotion, setPrefersReducedMotion] = useState(getInitialValue); useEffect(() => { // Check if window is available (client-side) if (typeof window === 'undefined') return; const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); // Listen for changes const handleChange = (event: MediaQueryListEvent) => { setPrefersReducedMotion(event.matches); }; // Use addEventListener for modern browsers mediaQuery.addEventListener('change', handleChange); return () => { mediaQuery.removeEventListener('change', handleChange); }; }, []); return prefersReducedMotion; } export default usePrefersReducedMotion; |