A production-ready motion library for React that provides comprehensive animation and gesture APIs for creating fluid, performant interactions.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Global configuration and feature bundle system for code splitting and performance optimization.
Provides global configuration for all motion components within its context.
/**
* Global configuration provider for motion components
* @param props - Configuration options
* @returns JSX element providing motion configuration context
*/
function MotionConfig(props: MotionConfigProps): JSX.Element;
interface MotionConfigProps {
/**
* Child components to apply configuration to
*/
children: React.ReactNode;
/**
* Default transition for all animations
*/
transition?: Transition;
/**
* Transform page coordinates (useful for zoom/pan interfaces)
*/
transformPagePoint?: (point: Point) => Point;
/**
* Reduced motion preference override
* - "always": Always reduce motion
* - "never": Never reduce motion
* - "user": Respect user's system preference (default)
*/
reducedMotion?: "always" | "never" | "user";
/**
* Custom prop validation function
*/
isValidProp?: (key: string) => boolean;
/**
* Enable/disable features globally
*/
features?: {
/**
* Enable layout animations (default: true)
*/
layout?: boolean;
/**
* Enable gesture handling (default: true)
*/
gestures?: boolean;
/**
* Enable exit animations (default: true)
*/
animations?: boolean;
};
}
interface Transition {
/**
* Animation duration in seconds
*/
duration?: number;
/**
* Delay before animation starts in seconds
*/
delay?: number;
/**
* Easing function or array for keyframes
*/
ease?: Easing | Easing[];
/**
* Animation type
*/
type?: "tween" | "spring" | "keyframes" | "inertia";
/**
* Number of times to repeat
*/
repeat?: number;
/**
* Type of repeat behavior
*/
repeatType?: "loop" | "reverse" | "mirror";
/**
* Delay between repeats
*/
repeatDelay?: number;
// Spring-specific options
bounce?: number;
damping?: number;
mass?: number;
stiffness?: number;
velocity?: number;
restSpeed?: number;
restDelta?: number;
}
interface Point {
x: number;
y: number;
}Usage Examples:
import { MotionConfig, motion } from "framer-motion";
// Global transition configuration
function GlobalTransitionExample() {
return (
<MotionConfig
transition={{
type: "spring",
stiffness: 260,
damping: 20
}}
>
<div className="space-y-4">
<motion.div
whileHover={{ scale: 1.1 }}
className="w-32 h-32 bg-blue-500 rounded"
>
Uses global spring config
</motion.div>
<motion.div
whileHover={{ scale: 1.1 }}
transition={{ type: "tween", duration: 0.2 }} // Override global
className="w-32 h-32 bg-red-500 rounded"
>
Overrides with tween
</motion.div>
</div>
</MotionConfig>
);
}
// Reduced motion configuration
function ReducedMotionExample() {
return (
<MotionConfig reducedMotion="user">
<motion.div
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
className="p-4 bg-green-500 text-white rounded"
>
Respects user's motion preferences
</motion.div>
</MotionConfig>
);
}
// Custom coordinate transformation
function TransformPointExample() {
const transformPagePoint = (point: Point) => ({
x: point.x * 0.5, // Scale down x coordinates
y: point.y * 0.5 // Scale down y coordinates
});
return (
<MotionConfig transformPagePoint={transformPagePoint}>
<motion.div
drag
className="w-32 h-32 bg-purple-500 rounded cursor-grab"
>
Drag coordinates are scaled
</motion.div>
</MotionConfig>
);
}Enables code splitting by loading animation features on demand.
/**
* Lazy loading wrapper for motion features
* @param props - LazyMotion configuration
* @returns JSX element providing lazy-loaded features
*/
function LazyMotion(props: LazyMotionProps): JSX.Element;
interface LazyMotionProps {
/**
* Child components that will use lazy-loaded features
*/
children: React.ReactNode;
/**
* Feature bundle to load (sync or async)
*/
features: FeatureBundle | (() => Promise<FeatureBundle>);
/**
* Strict mode - only allow features defined in bundle (default: true)
*/
strict?: boolean;
}
interface FeatureBundle {
/**
* Animation feature definitions
*/
animation?: FeatureDefinition;
/**
* Exit animation features
*/
exit?: FeatureDefinition;
/**
* Gesture handling features
*/
gestures?: FeatureDefinition;
/**
* Drag interaction features
*/
drag?: FeatureDefinition;
/**
* Layout animation features
*/
layout?: FeatureDefinition;
/**
* Measurement and projection features
*/
measureLayout?: FeatureDefinition;
}
interface FeatureDefinition {
/**
* Feature implementation functions
*/
[key: string]: any;
}Pre-built Feature Bundles:
/**
* Minimal DOM features bundle (animations only)
*/
const domMin: FeatureBundle;
/**
* DOM animation features bundle (animations + gestures)
*/
const domAnimation: FeatureBundle;
/**
* Maximum DOM features bundle (all features)
*/
const domMax: FeatureBundle;Usage Examples:
import { LazyMotion, domAnimation, domMax, m } from "framer-motion";
// Synchronous feature loading
function SyncLazyMotionExample() {
return (
<LazyMotion features={domAnimation}>
<m.div
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
className="w-32 h-32 bg-blue-500 rounded cursor-pointer"
>
Lazy loaded gestures
</m.div>
</LazyMotion>
);
}
// Asynchronous feature loading
function AsyncLazyMotionExample() {
return (
<LazyMotion
features={() => import("framer-motion").then(mod => mod.domMax)}
strict={false}
>
<m.div
drag
whileHover={{ scale: 1.1 }}
className="w-32 h-32 bg-green-500 rounded cursor-grab"
>
Async loaded features
</m.div>
</LazyMotion>
);
}
// Custom feature bundle
function CustomFeatureExample() {
const customFeatures = async () => {
// Load only specific features
const { domAnimation } = await import("framer-motion");
return domAnimation;
};
return (
<LazyMotion features={customFeatures}>
<m.div
animate={{ rotate: 360 }}
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
className="w-16 h-16 bg-purple-500 rounded"
>
Custom bundle
</m.div>
</LazyMotion>
);
}Global configuration utilities that affect all Framer Motion instances.
/**
* Global motion configuration object from motion-utils
*/
interface MotionGlobalConfig {
/**
* Skip animations entirely (useful for testing)
*/
skipAnimations?: boolean;
/**
* Use reduced motion globally
*/
useManualTiming?: boolean;
/**
* Custom easing functions
*/
easing?: {
[key: string]: (t: number) => number;
};
}
/**
* Access to global motion configuration
*/
const MotionGlobalConfig: MotionGlobalConfig;Usage Example:
import { MotionGlobalConfig } from "framer-motion";
// Configure globally (typically in app setup)
MotionGlobalConfig.skipAnimations = process.env.NODE_ENV === "test";
// Custom easing functions
MotionGlobalConfig.easing = {
...MotionGlobalConfig.easing,
customEase: (t: number) => t * t * (3 - 2 * t) // Smoothstep
};
function GlobalConfigExample() {
return (
<motion.div
animate={{ x: 100 }}
transition={{ ease: "customEase", duration: 1 }}
>
Uses custom global easing
</motion.div>
);
}Hooks for detecting and responding to reduced motion preferences.
/**
* Detect user's reduced motion preference
* @returns Boolean indicating if reduced motion is preferred
*/
function useReducedMotion(): boolean;
/**
* Configure reduced motion behavior for components
* @returns Configuration object for reduced motion
*/
function useReducedMotionConfig(): {
/**
* Whether reduced motion is currently active
*/
shouldReduceMotion: boolean;
/**
* Override reduced motion setting
*/
setReducedMotion: (reduce: boolean | "user") => void;
};Usage Examples:
import { motion, useReducedMotion, useReducedMotionConfig } from "framer-motion";
// Basic reduced motion detection
function ReducedMotionExample() {
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
animate={{
x: shouldReduceMotion ? 0 : 100,
transition: {
duration: shouldReduceMotion ? 0 : 1
}
}}
className="w-32 h-32 bg-blue-500 rounded"
>
Motion respects user preference
</motion.div>
);
}
// Advanced reduced motion configuration
function AdvancedReducedMotionExample() {
const { shouldReduceMotion, setReducedMotion } = useReducedMotionConfig();
return (
<div>
<div className="mb-4 space-x-2">
<button
onClick={() => setReducedMotion(false)}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Enable Motion
</button>
<button
onClick={() => setReducedMotion(true)}
className="px-4 py-2 bg-red-500 text-white rounded"
>
Disable Motion
</button>
<button
onClick={() => setReducedMotion("user")}
className="px-4 py-2 bg-gray-500 text-white rounded"
>
Respect User Preference
</button>
</div>
<motion.div
animate={{
rotate: shouldReduceMotion ? 0 : 360,
scale: shouldReduceMotion ? 1 : [1, 1.2, 1]
}}
transition={{
duration: shouldReduceMotion ? 0 : 2,
repeat: shouldReduceMotion ? 0 : Infinity
}}
className="w-32 h-32 bg-green-500 rounded"
>
Configurable motion
</motion.div>
<p className="mt-2 text-sm">
Reduced motion: {shouldReduceMotion ? "Active" : "Inactive"}
</p>
</div>
);
}Utilities for detecting available features and capabilities.
/**
* Check if running in browser environment
* @returns Boolean indicating browser environment
*/
function isBrowser(): boolean;
/**
* Detect available animation features
* @returns Object describing available features
*/
interface FeatureDetection {
/**
* Web Animations API support
*/
waapi: boolean;
/**
* CSS transforms support
*/
transforms: boolean;
/**
* Touch/pointer events support
*/
touch: boolean;
/**
* Reduced motion preference
*/
reducedMotion: boolean;
}
/**
* Browser environment detection
*/
const isBrowser: boolean;Usage Example:
import { isBrowser } from "framer-motion";
import { useEffect, useState } from "react";
function FeatureDetectionExample() {
const [features, setFeatures] = useState<any>(null);
useEffect(() => {
if (isBrowser()) {
// Detect browser capabilities
const detection = {
waapi: "animate" in document.createElement("div"),
transforms: "transform" in document.createElement("div").style,
touch: "ontouchstart" in window,
reducedMotion: window.matchMedia("(prefers-reduced-motion: reduce)").matches
};
setFeatures(detection);
}
}, []);
if (!isBrowser()) {
return <div>Server-side rendering</div>;
}
return (
<div>
<h3>Browser Capabilities:</h3>
{features && (
<ul className="list-disc pl-6">
<li>Web Animations API: {features.waapi ? "✅" : "❌"}</li>
<li>CSS Transforms: {features.transforms ? "✅" : "❌"}</li>
<li>Touch Support: {features.touch ? "✅" : "❌"}</li>
<li>Reduced Motion: {features.reducedMotion ? "✅" : "❌"}</li>
</ul>
)}
</div>
);
}Configuration options for optimizing animation performance.
/**
* Configure performance settings
*/
interface PerformanceConfig {
/**
* Enable GPU acceleration hints
*/
useGPUAcceleration?: boolean;
/**
* Batch DOM updates
*/
batchUpdates?: boolean;
/**
* Throttle animation frame rate
*/
maxFrameRate?: number;
/**
* Enable transform optimization
*/
optimizeTransforms?: boolean;
}Usage Example:
// Configure performance at app level
function App() {
return (
<MotionConfig
transition={{
type: "spring",
stiffness: 260,
damping: 20
}}
>
<LazyMotion features={domAnimation}>
<div className="app">
{/* App content with optimized motion */}
</div>
</LazyMotion>
</MotionConfig>
);
}
// Environment-specific configuration
const getMotionConfig = () => {
if (process.env.NODE_ENV === "development") {
return { reducedMotion: "never" }; // Always animate in dev
}
if (process.env.NODE_ENV === "test") {
MotionGlobalConfig.skipAnimations = true; // Skip in tests
}
return { reducedMotion: "user" }; // Respect user preference in production
};Responsive Motion:
function ResponsiveMotion() {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth < 768);
checkMobile();
window.addEventListener("resize", checkMobile);
return () => window.removeEventListener("resize", checkMobile);
}, []);
return (
<MotionConfig
transition={{
type: isMobile ? "tween" : "spring",
duration: isMobile ? 0.2 : 0.6
}}
>
{/* Motion components adapt to screen size */}
</MotionConfig>
);
}Theme-based Configuration:
function ThemedMotion({ theme, children }: { theme: "light" | "dark", children: React.ReactNode }) {
const config = {
light: {
transition: { type: "spring", stiffness: 300 },
reducedMotion: "user"
},
dark: {
transition: { type: "tween", duration: 0.3 },
reducedMotion: "never"
}
};
return (
<MotionConfig {...config[theme]}>
{children}
</MotionConfig>
);
}Progressive Enhancement:
function ProgressiveMotion({ children }: { children: React.ReactNode }) {
const [features, setFeatures] = useState(domMin);
useEffect(() => {
// Progressively load more features
const loadFullFeatures = async () => {
const { domMax } = await import("framer-motion");
setFeatures(domMax);
};
// Load after initial render
const timer = setTimeout(loadFullFeatures, 100);
return () => clearTimeout(timer);
}, []);
return (
<LazyMotion features={features}>
{children}
</LazyMotion>
);
}