What is prefers-reduced-motion?

prefers-reduced-motion: prefers-reduced-motion is a CSS media feature that reports whether the user has asked the operating system to minimize nonessential animation.

Motion on screen can trigger dizziness, nausea or headaches for people with vestibular disorders, and it distracts many others. Every major operating system has a setting to reduce it: Reduce Motion on macOS and iOS, the animation effects setting on Windows, and Remove animations on Android. Browsers expose that choice to CSS through the prefers-reduced-motion media feature, which has two values: no-preference and reduce. JavaScript can read the same value with matchMedia.

How it works

css
.card {
  transition: transform 140ms ease-out, opacity 140ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .card {
    transition: opacity 140ms ease-out;
  }
}

Reduced motion does not mean no change at all. The usual approach removes movement, scaling, parallax and spinning, and keeps quick opacity or color changes so state changes stay clear. Removing every transition can make interfaces feel broken, because a panel that appears with no cue at all is easy to miss. In Tailwind CSS, the motion-reduce: and motion-safe: variants map to this media query, so motion-safe:animate-bounce animates only for users who have not asked for less motion.

  • Remove parallax, scroll-linked transforms and large slide or zoom transitions.
  • Stop autoplaying loops such as marquees and animated backgrounds, or offer a pause control.
  • Replace spring-based position changes with instant updates or a short crossfade.
  • Keep functional feedback: focus rings, color changes and progress indicators should still appear.
  • Set scroll-behavior: auto so anchor links and scripted scrolling jump instead of gliding across the page.

In JavaScript and React

Animation driven from JavaScript is out of reach of CSS media queries, so read the preference and branch:

tsx
"use client"
import type { ReactNode } from "react"
import { motion, useReducedMotion } from "motion/react"

export function Reveal({ children }: { children: ReactNode }) {
  const reduce = useReducedMotion()
  return (
    <motion.div
      initial={reduce ? false : { opacity: 0, y: 12 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: reduce ? 0 : 0.2 }}
    >
      {children}
    </motion.div>
  )
}

Without a library, window.matchMedia("(prefers-reduced-motion: reduce)") returns a query list with a matches boolean and a change event. On the standards side, WCAG 2.3.3 Animation from Interactions (level AAA) asks that motion triggered by interaction can be turned off, and 2.2.2 Pause, Stop, Hide (level A) covers content that moves on its own for more than five seconds.

How MiniDev UI handles it

Reduced motion is a rule in the kit's design spec, not an option. The global stylesheet cuts transitions and animations to near zero under reduce, and components that animate in JavaScript check useReducedMotion: Number roll swaps digits without springs, Tabs stops animating its indicator, Marquee stops scrolling, and LightProvider holds the light still instead of drifting. For more on purposeful motion, see micro-interactions.

MarqueeuiAn infinitely scrolling Tailwind strip that loops its children horizontally, duplicated for a gapless cycle, and stops when users prefer reduced motion.npx shadcn@latest add ui.minidev.pro/r/marquee.json