Skip to content

How It Works

The reduced motion plugin operates through a simple but effective mechanism that integrates seamlessly with Vue Flip's middleware system.

Technical Implementation

1. Media Query Detection

The plugin uses the window.matchMedia API to detect if the user has enabled reduced motion in their system settings:

typescript
const mm = window.matchMedia('(prefers-reduced-motion: reduce)')
let isReducedMotion = mm.matches === true

This creates a media query listener that checks the current state of the user's motion preferences.

2. Middleware Integration

The plugin registers middleware functions with the Flip Manager that intercept animation requests:

typescript
function detachMiddleware (_id: string, _el: Element, config: FlipElementConfig) {
  return isReducedMotion && config.respectReducedMotion === false
}

function attachMiddleware (_id: string, _el: Element, config: FlipElementConfig) {
  return isReducedMotion && config.respectReducedMotion === false
}

These middleware functions:

  • Intercept both attach and detach animation requests
  • Check if reduced motion is preferred by the user
  • Check if the specific element is configured to respect reduced motion
  • Return true to prevent the animation when conditions are met

3. Dynamic Response

The plugin listens for changes to the user's motion preferences:

typescript
mm.addEventListener('change', e => (isReducedMotion = e.matches))

This means if a user changes their system settings while using your application, the plugin will immediately respond to the new preference without requiring a page reload.

4. Plugin Registration

When the plugin is registered with the Flip Manager:

typescript
flipManager.addDetachMiddleware(detachMiddleware)
flipManager.addAttachMiddleware(attachMiddleware)

The middleware functions are added to the Flip Manager's middleware chain, allowing them to intercept all animation requests.

Configuration Logic

The plugin adds a respectReducedMotion property to the FlipElementConfig:

ValueBehavior
true (default)Respects user's motion preferences
falseAlways animates regardless of user preferences
undefinedUses the default behavior (respects preferences)

Override Logic

The middleware logic works as follows:

typescript
// For detach animations
return isReducedMotion && config.respectReducedMotion === false

// For attach animations
return isReducedMotion && config.respectReducedMotion === false

This means:

  • If isReducedMotion is false (user doesn't prefer reduced motion), animations always play
  • If isReducedMotion is true but respectReducedMotion is false, animations still play (override)
  • If isReducedMotion is true and respectReducedMotion is true or undefined, animations are prevented

Type Augmentation

The plugin automatically extends TypeScript types through module augmentation:

typescript
// In types.ts
export interface ReducedMotionFlipElementConfig {
  respectReducedMotion?: boolean
}

declare module '@vue-gsap-flip/core' {
  interface FlipElementConfigAugmentation extends ReducedMotionFlipElementConfig {}
}

This ensures that the respectReducedMotion property is available in TypeScript when using the plugin.

Cleanup

The plugin returns a cleanup function when installed:

typescript
return () => {
  flipManager.removeDetachMiddleware(detachMiddleware)
  flipManager.removeAttachMiddleware(attachMiddleware)
}

This allows the plugin to be properly uninstalled if needed, removing the middleware functions from the Flip Manager.

Performance Considerations

  • The media query listener is lightweight and only triggers when system preferences change
  • Middleware functions are simple boolean checks with minimal performance impact
  • No polling or continuous monitoring is required
  • The plugin only activates when reduced motion is actually preferred

Released under the MIT License.