Skip to content
Corsair UI
Browse React Native

React NativeHooksNo. 21 of 22

useReducedMotion

Whether Reduce Motion is on in the device's accessibility settings, following changes while the app is open.

Preview

Loading the preview

The gallery's web build, through react-native-web. On a phone the same code draws native views.

Installation

npx shadcn@latest add @corsair-native/use-reduced-motion

The app's components.json needs the @corsair-native registry first; see Installation. The files land in your project as source: edit them like your own code.

API

Read from the source's own comments and types. Props marked * are required.

useReducedMotionHook

Whether "Reduce motion" is on in the device's accessibility settings (on the web, prefers-reduced-motion). It follows changes while the app is open. The first render of the first component uses false until the system answers; later mounts start with the last answer, so they do not animate when they should not.

Returns boolean.

const reduced = useReducedMotion();
Animated.timing(opacity, { toValue: 1, duration: reduced ? 0 : 200, useNativeDriver: true });

Compatibility

Expo SDK
54 and 57, both checked in CI
React Native
0.81 and 0.86, New Architecture
Web
Expo's web target, through react-native-web

Source

1 file, installed as source you own
use-reduced-motion.tsView on GitHub
import { useEffect, useState } from "react";
import { AccessibilityInfo } from "react-native";

/** The last answer from the system, so components mounted later start with it. */
let lastKnown = false;

/**
 * Whether "Reduce motion" is on in the device's accessibility settings (on
 * the web, `prefers-reduced-motion`). It follows changes while the app is
 * open. The first render of the first component uses `false` until the system
 * answers; later mounts start with the last answer, so they do not animate
 * when they should not.
 *
 * @example
 * const reduced = useReducedMotion();
 * Animated.timing(opacity, { toValue: 1, duration: reduced ? 0 : 200, useNativeDriver: true });
 */
function useReducedMotion(): boolean {
  const [reduced, setReduced] = useState(lastKnown);

  useEffect(() => {
    let active = true;
    const update = (value: boolean) => {
      lastKnown = value;
      if (active) setReduced(value);
    };
    AccessibilityInfo.isReduceMotionEnabled().then(update, () => {});
    const subscription = AccessibilityInfo.addEventListener("reduceMotionChanged", update);
    return () => {
      active = false;
      // react-native-web returns nothing where the browser lacks matchMedia.
      subscription?.remove();
    };
  }, []);

  return reduced;
}

export { useReducedMotion };