Skip to content

Accessibility · Next.js (App Router)

How to support prefers-reduced-motion in Next.js (App Router)

For people with vestibular disorders, parallax and large motion cause genuine nausea and dizziness — which is why every major OS has a system-level setting. The setting is already switched on for these visitors; the site just has to read it. One media query covers the whole stylesheet, and it is WCAG 2.3.3.

The fix for Next.js (App Router)

13x detects your framework from the response and hands you this version rather than the generic one — below 50% confidence it hedges and gives you the generic one instead.

Add the blanket rule to app/globals.css:

css code
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Near-zero rather than none: at 0s the animationend event never fires, and anything sequencing on it stalls.

If you use Framer Motion, it reads the preference for you — wrap the tree once and every motion component respects it:

tsx code
// app/providers.tsx
"use client";

import { MotionConfig } from "framer-motion";

export function Providers({ children }: { children: React.ReactNode }) {
  return <MotionConfig reducedMotion="user">{children}</MotionConfig>;
}

reducedMotion="user" keeps opacity transitions and drops transform ones, which is usually the behaviour you want rather than freezing everything.

On a different stack? The general version of this fix explains what 13x checks and why it matters, without assuming a framework.

Check your Next.js (App Router) site

113 deterministic checks against your live URL, in about 30 seconds. Framework detected from the response, so every fix comes back in the form your stack actually uses.

No signup. Results in 30 seconds.