Guideline 4.0

Guideline 4.0 - Design: Reduced Motion Setting Not Respected

Low SeverityEasy FixTypical Fix: 2-4 hours0 Reports
Also known as:Parallax scrolling effects persist with Reduce Motion enabledSpinning or rotating loading indicators do not simplifyScreen transition animations (zoom, slide, flip) ignore the settingAuto-playing animated backgrounds or hero banners continue animatingLottie or Rive animations play at full complexity regardless of accessibility preference

Our Take

Apple rejected your app because it does not respect the Reduce Motion accessibility setting. When users enable Settings → Accessibility → Motion → Reduce Motion, your app continues to display parallax effects, spinning animations, zoom transitions, or other motion-intensive UI. Users with vestibular disorders or motion sensitivity rely on this setting to prevent dizziness and nausea. Apple expects all apps to detect the Reduce Motion preference and provide simplified, crossfade-style alternatives for every animation.

Resolution Guide

01

Detect the Reduce Motion preference

In SwiftUI, use the environment value:

   @Environment(\.accessibilityReduceMotion) var reduceMotion

In UIKit, check the static property:


   UIAccessibility.isReduceMotionEnabled
02

Replace complex animations with crossfades

When Reduce Motion is on, swap zoom, spin, and slide animations for simple opacity transitions:

   withAnimation(reduceMotion ? .none : .spring(duration: 0.4)) {
       showDetail = true
   }
03

Disable parallax effects

Remove any custom parallax layers or set their motion multiplier to zero when Reduce Motion is enabled. If using UIInterpolatingMotionEffect, guard it:

   if !UIAccessibility.isReduceMotionEnabled {
       view.addMotionEffect(parallaxEffect)
   }
04

Simplify loading indicators

Replace spinning indicators with a static pulsing dot or a simple progress bar:

   if reduceMotion {
       ProgressView()  // system default respects Reduce Motion
   } else {
       CustomSpinnerView()
   }
05

Use the .transaction modifier for view transitions

SwiftUI’s matchedGeometryEffect and NavigationStack transitions can be made motion-safe:

   .transaction { transaction in
       if reduceMotion {
           transaction.animation = nil
       }
   }
06

Audit all Lottie/Rive animations

Either pause animated assets entirely or switch to a simplified, low-motion variant when Reduce Motion is enabled.

07

Test with Reduce Motion enabled

Go to Settings → Accessibility → Motion → Reduce Motion and walk through every screen. No spinning, zooming, parallax, or auto-play animation should be visible.

Example Rejection Email

From:Apple App Review Team
Subject:Guideline 4.0 - Design: Reduced Motion Setting Not Respe
Your app does not respect the Reduce Motion accessibility setting. Specifically, when the reviewer enabled Reduce Motion in Settings → Accessibility → Motion, the following animations continued to play: (1) the spinning loading indicator on the home screen, (2) parallax scrolling effects on the featured content cards, and (3) the zoom-in transition between screens. Please update your app to detect the Reduce Motion setting and provide appropriate alternatives for all animations.

Consider Appealing

Do not appeal. This is a straightforward accessibility fix that typically takes 2–4 hours. Check the @Environment(\.accessibilityReduceMotion) value and provide crossfade or static alternatives for every animation. Resubmit once the fix is verified with Reduce Motion enabled.

Generate Appeal

Before & After

Before — Rejected

// Spinning loader that ignores Reduce Motion

struct SpinnerView: View {

@State private var rotation: Double = 0


var body: some View {

Image(systemName: "arrow.triangle.2.circlepath")

.rotationEffect(.degrees(rotation))

.onAppear {

withAnimation(.linear(duration: 1).repeatForever(autoreverses: false)) {

rotation = 360

}

}

}

}

After — Approved

// Motion-safe spinner with Reduce Motion fallback

struct SpinnerView: View {

@State private var rotation: Double = 0

@Environment(\.accessibilityReduceMotion) var reduceMotion


var body: some View {

if reduceMotion {

ProgressView() // system spinner respects Reduce Motion

} else {

Image(systemName: "arrow.triangle.2.circlepath")

.rotationEffect(.degrees(rotation))

.onAppear {

withAnimation(.linear(duration: 1).repeatForever(autoreverses: false)) {

rotation = 360

}

}

}

}

}

What changed: When Reduce Motion is enabled, replace the custom spinning animation with the system ProgressView, which automatically adapts to accessibility settings. The custom spinner only runs when the user has not requested reduced motion.

Before — Rejected

// Parallax card effect on scroll — ignores accessibility

struct ParallaxCard: View {

let offset: CGFloat


var body: some View {

ZStack {

Image("background")

.offset(y: offset * 0.3) // parallax movement

VStack {

Text("Featured")

.font(.title)

}

}

}

}

After — Approved

// Parallax card with Reduce Motion guard

struct ParallaxCard: View {

let offset: CGFloat

@Environment(\.accessibilityReduceMotion) var reduceMotion


var body: some View {

ZStack {

Image("background")

.offset(y: reduceMotion ? 0 : offset * 0.3)

VStack {

Text("Featured")

.font(.title)

}

}

}

}

What changed: The parallax offset multiplier is set to zero when Reduce Motion is enabled. The background image stays fixed while the content scrolls normally, eliminating the motion that can cause vestibular discomfort.

Community Solutions · 0

Sign in to share your solution.

More Guideline 4 (Design) rejections

View all Guideline 4 rejections