Skip to content

fix(design-system-react-native): respect reduced motion in Spinner - #1672

Closed
georgewrmarshall wants to merge 1 commit into
mainfrom
cursor/spinner-reduced-motion-08f8
Closed

georgewrmarshall wants to merge 1 commit into
mainfrom
cursor/spinner-reduced-motion-08f8

Conversation

@georgewrmarshall

@georgewrmarshall georgewrmarshall commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Description

v81 follow-up to #1665. That PR, by Juanmi (juanmigdr), replaced the Reanimated withRepeat rotation in Spinner with a core Animated.loop on the native driver (useNativeDriver: true, isInteraction: false). Continuous Reanimated shadow-tree commits were competing with layout-animation commits on Android and the spinner could stop the app. The native driver rotates the view on the UI thread without those commits.

Reanimated's default ReduceMotion.System used to skip that infinite animation when the OS reduce-motion setting was on. The native-driver loop does not consult that setting, so the spinner kept spinning for people who had asked for less motion.

This PR only adds that missing check. There is no shared reduced-motion hook in the repo. On mount, Spinner reads AccessibilityInfo.isReduceMotionEnabled() and subscribes to reduceMotionChanged, removing the subscription on unmount. While reduced motion is on, the loop is not started, or it is stopped and rotation is reset to 0deg, so the icon shows as a static ring. Turning the setting off starts the same native-driver loop. A parent re-render does not recreate it. A read that resolves after unmount, or after a newer reduceMotionChanged event, is ignored so the loop does not flicker or update state after unmount. If the platform cannot report the setting, the spinner keeps spinning, which is the previous behavior.

Related issues

Builds on #1665, which merged for the v80 release. This does not replace or close that PR.

Manual testing steps

  1. React Native Web: run yarn workspace @metamask/storybook-react-native storybook:web and open Temp Components/Spinner (and a loading Button / ButtonBase, which renders Spinner).
    • Reduce motion off: the icon rotates once per second. Loading text stays still.
    • Reduce motion on: emulate prefers-reduced-motion: reduce, or turn on the OS setting. The icon is a static ring and does not rotate.
    • Toggle the setting while the story is open. The spinner starts when reduced motion turns off, and stops and resets when it turns on.
  2. iOS: run Storybook on a simulator or device and repeat those checks with Settings → Accessibility → Motion → Reduce Motion off, then on, then toggled while the spinner is visible.
  3. Android: run Storybook on a device or emulator and repeat the same checks with Settings → Accessibility → Remove animations. Android also treats Developer options → Animator duration scale → Animation off as reduce motion. The spinner stays static while the setting is on and rotates while it is off, including after a live toggle.

Screenshots/Recordings

A still before/after is not a useful comparison. The icon artwork is unchanged, and a single frame of a rotating ring does not show whether reduced motion is respected.

Before

With reduced motion off, the ring spins (same as #1665). With reduced motion on, the ring still spun, because the native-driver loop ignored the OS setting.

After

With reduced motion off, the ring spins once per second on the native driver. With reduced motion on, the ring stays still at 0°.

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs
  • I've completed the PR template to the best of my ability
  • I’ve included tests if applicable
  • I’ve documented my code using JSDoc format if applicable

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
Open in Web Open in Cursor 

Note

Low Risk
Single-component UI/accessibility behavior with extensive unit tests; no data, auth, or cross-cutting infra changes.

Reviewed by Cursor Bugbot for commit b567586. Bugbot is set up for automated code reviews on this repo. Configure here.

@georgewrmarshall
georgewrmarshall requested a review from a team as a code owner November 6, 2026 22:57
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Links

Compare the preview for this pull request with the latest Storybooks from the main branch.

🔀 Pull Request Preview

🌳 Main Branch (Latest)

The native-driver loop from #1665 spins even when the OS reduce-motion
setting is on. Reanimated's ReduceMotion.System used to suppress that
loop. Read AccessibilityInfo on mount, subscribe to reduceMotionChanged,
and hold the icon still while the setting is enabled.

Co-authored-by: Juanmi <95381763+juanmigdr@users.noreply.github.com>
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/spinner-reduced-motion-08f8 branch from 4d3072b to b567586 Compare November 6, 2026 23:03
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Links

Compare the preview for this pull request with the latest Storybooks from the main branch.

🔀 Pull Request Preview

🌳 Main Branch (Latest)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants