Skip to content
A cross platform react hook that indicates whether a user's OS is configured to "Reduce motion" for accessibility purposes
JavaScript
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
native
src/targets
.eslintrc.js
.gitignore
.npmignore
README.md
babel.config.js
jest.config.js
package.json
rollup.config.js
yarn.lock

README.md

React Reduce Motion

Installation and Usage

❗ React Reduce Motion requires react ^16.8.0 or for native, requires react-native ^0.60.

yarn add react-reduce-motion

React Reduce Motion provides a react hook that exposes the "Reduce Motion" preference of a user's operating system to your componets.

import { useReduceMotion } from 'react-reduce-motion';

Why?

Building animations in React is fun! Especially if you're using a library like react-spring. I recently had some fun messing around with react-spring and learned that animations are not fun for everyone.

Vestibular dysfunction, a balance disorder of the inner ear, is surprisingly common among US adults. A study from the early 2000's found that approximately 69 million Americans had vestibular dysfunction which results in vertigo, nausea, migraines and hearing loss. Many people affected by vestibular dysfunction will choose to set the "Reduce motion" setting in their OS. In macOS it's found in the accessibility settings.

A macOS system preferences screen with the "Reduce motion" checkbox checked

If you're including animations in your app, consider optionally reducing their intensity so that everyone can enjoy your app. There are a couple ways you can do this with React Reduce Motion.

  1. If you're using react-spring, disable animations entirely using a global:
import { Globals } from 'react-spring'
import { useReduceMotion } from 'react-reduce-motion';

const MyApp = () => {
  const prefersReducedMotion = useReduceMotion()
  React.useEffect(() => {
    Globals.assign({
      skipAnimation: prefersReducedMotion,
    })
  }, [prefersReducedMotion])
  return ...
}
  1. Reduce the animation intensity using a heuristic of your choosing:
import { useReduceMotion } from 'react-reduce-motion';

function ParallaxAnimatedButton({ rotation = 10, scale = 1.2 }) {
  const buttonRef = React.useRef();
  const reduceMotion = useReduceMotion();
  const defaultTransform = [0, 0, 1]
  // This is where we choose the animation intensity depending on user preference.
  const actualRotation = reduceMotion ? rotation / 3 : rotation;
  const actualScale = reduceMotion ? 1.01 : scale;
  const [props, set] = useSpring(() => ({
    xys: defaultTransform,
    config: { mass: 7, tension: 500, friction: 40 }
  }));
  return (
    <animated.button
      ref={buttonRef}
      className="springy-button"
      onMouseMove={({ clientX, clientY }) =>
        set({ xys: calc(actualRotation, actualScale, clientX, clientY, buttonRef.current) })
      }
      onMouseLeave={() => set({ xys: defaultTransform })}
      style={{
        transform: props.xys.to(transform),
      }}
    >
      Hover over me!
    </animated.button>
  );
}

Before:

A very intensely animated button

After:

A subtly animated button

  const actualRotation = reduceMotion ? rotation / 3 : rotation;

The above snippet is where the heuristic is applied. Depending on what you're animating, you need to make your own decision. See the Resources section below as your guide.

Interactive example

Native

To use React Reduce Motion with React Native, import the native build use the hook as demonstrated above.

❗ The native react hook provided by React Reduce Motion requires react-native ^0.60.

import { useReduceMotion } from 'react-reduce-motion/native';

Implementation

The web version of this package is based on prefers-reduced-motion from Media Queries Level 5. See browser support here.

The native version depends on React Native's AccessibilityInfo API which provides a cross platform isReduceMotionEnabled function. This was introduced in React Native v0.60.

Inspiration

Writing a blog post about my experience learning react-spring helped me realize the need for a package that promotes building accessible animations. Read it here and you'll learn how I implemented it. A conversation with Paul, the creator of react-spring, spurred me to contribute this work.

Resources

WCAG 2.1 - Guideline 2.3 Seizures and Physical Reactions

Do not design content in a way that is known to cause seizures or physical reactions. reference

Motion animation triggered by interaction can be disabled, unless the animation is essential [emphasis added] to the functionality or the information being conveyed. reference

You can’t perform that action at this time.