# Accessibility
How to design accessible animations with Framer Motion.Framer Motion provides the the useReducedMotion hook to help you support users who have enabled their device’s Reduced Motion setting.
import { useReducedMotion } from "framer-motion"
// In your component...
const shouldReduceMotion = useReducedMotion()
There are already some excellent guides about why and how we should design accessible animations, like those at A List Apart and Smashing Magazine.
Practically speaking, the main takeaways are that we should keep educational transitions but be aware of motion sickness. So that means replacing position transitions on large elements with opacity transitions, disabling auto-playing videos, and disabling parallax animations.
In this guide we'll briefly take a look at how we can use the useReducedMotion
hook to implement each.
# Replace position transitions with opacity
When Reduced Motion is enabled on iOS, the operating system still animates between states to help users transition between each context. But instead of the default scale and position animations, it fades content in and out.
We can achieve this in Framer Motion by passing different values to animate
based on whether useReducedMotion
returns true
or not.
function Sidebar({ isOpen }) {
const shouldReduceMotion = useReducedMotion()
let animate
if (isOpen) {
animate = shouldReduceMotion ? { opacity: 1 } : { x: 0 }
} else {
animate = shouldReduceMotion
? { opacity: 0 }
: { x: "-100%" }
}
return <motion.div animate={animate} />
}
# Disable auto-playing videos
useReducedMotion
isn’t only compatible with the Framer Motion API. It returns a simple boolean, so you can use it for any purpose, like disabling the autoplay of a background video
element.
function BackgroundVideo() {
const shouldReduceMotion = useReducedMotion()
return <video autoplay={!shouldReduceMotion} />
}
# Disable parallax animations
Parallax animations can be very unpleasant for people pre-disposed to motion sickness.
To build parallax, we usually get scrollY
from useViewportScroll
, and create a new MotionValue
via passing that to useTransform
which will update's a motion
component's y
position as the scroll value changes.
To disable this for reduced motion devices, we can conditionally pass this MotionValue
to the animating element.
function Parallax() {
const shouldReduceMotion = useReducedMotion()
const { scrollY } = useViewportScroll()
const y = useTransform(scrollY, [0, 1], [0, -0.2], {
clamp: false,
})
return (
<motion.div style={{ y: shouldReduceMotion ? 0 : y }} />
)
}