eMoosavi
Weekly frontend dev braindumps
Crafting Reusable Animations with React and framer-motion
React Components

Crafting Reusable Animations with React and framer-motion

Master the Art of Animations in React with Advanced framer-motion Techniques

Jul 04, 2024 - 10:004 min read

Crafting Reusable Animations with React and framer-motion

Animations can breathe life into your web applications, providing a more dynamic and engaging user experience. But managing animations in large applications can become cumbersome if not approached correctly. In this post, we will explore how to craft reusable animations in React using the powerful framer-motion library. We'll dive into advanced techniques that make managing animations efficient and scalable.

Why framer-motion?

framer-motion is a production-ready motion library for React. It offers a simple yet powerful API to create complex animations with clean syntax. Framer-motion handles the animation loop, offering a declarative approach, similar to how React handles UI state.

Here's a simple example to illustrate how to animate a box:

import { motion } from 'framer-motion';

const AnimatedBox = () => (
  <motion.div animate={{ x: 100 }} />
);

This snippet moves the box 100px to the right. Simple, right? But this is just scratching the surface.

Animating Complex States with Variants

Variants make managing complex animations easier by defining multiple states and transition timings. For example, let's create a button with different hover and tap states:

const buttonVariants = {
  hover: { scale: 1.1 },
  tap: { scale: 0.9 }
};

const AnimatedButton = () => (
  <motion.button
    variants={buttonVariants}
    whileHover="hover"
    whileTap="tap"
  >
    Click Me
  </motion.button>
);

In this setup, the button scales up on hover and scales down when tapped.

Using Keyframes for Advanced Animations

Framer-motion supports keyframe sequences for animating between multiple states. This is particularly useful for creating fluid and complex animations.

const keyframeAnimation = {
  animate: {
    x: [0, 100, 50, 100, 0],
    transition: {
      duration: 2,
      ease: "easeInOut"
    }
  }
};

const KeyframeAnimationComponent = () => (
  <motion.div {...keyframeAnimation}>Keyframe Animation</motion.div>
);

Creating Reusable Animation Components

Creating reusable components for animations promotes code reusability and clean architecture. For instance, a custom FadeIn component can be used to wrap any element:

const fadeInVariant = {
  hidden: { opacity: 0 },
  visible: { opacity: 1 }
};

const FadeIn = ({ children }) => (
  <motion.div
    initial="hidden"
    animate="visible"
    variants={fadeInVariant}
  >
    {children}
  </motion.div>
);

// Usage
const App = () => (
  <FadeIn>
    <h1>Hello World</h1>
  </FadeIn>
);

Advanced Stagger Animations

Stagger animations animate children with a delay, creating visually appealing sequences. framer-motion makes this straightforward with its staggerChildren property.

const containerVariants = {
  visible: {
    transition: {
      staggerChildren: 0.2
    }
  }
};

const itemVariants = {
  hidden: { opacity: 0 },
  visible: { opacity: 1 }
};

const StaggeredList = () => (
  <motion.ul
    initial="hidden"
    animate="visible"
    variants={containerVariants}
  >
    {[...Array(5)].map((_, i) => (
      <motion.li key={i} variants={itemVariants} />
    ))}
  </motion.ul>
);

Implementing Scroll-based Animations

Scroll-based animations trigger as users scroll through the page. This can be easily achieved with the useAnimation hook and an intersection observer.

import { useAnimation } from 'framer-motion';
import { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';

const ScrollAnimation = () => {
  const controls = useAnimation();
  const [ref, inView] = useInView({ triggerOnce: true });

  useEffect(() => {
    if (inView) {
      controls.start('visible');
    }
  }, [inView, controls]);

  return (
    <motion.div
      ref={ref}
      initial="hidden"
      animate={controls}
      variants={{
        hidden: { opacity: 0 },
        visible: { opacity: 1 }
      }}
    >
      Scroll to animate
    </motion.div>
  );
};

Animating SVGs

Animating SVGs adds another layer of sophistication to your UI. Framer-motion provides support for animating path attributes, creating stunning visual effects.

const svgVariants = {
  hidden: { pathLength: 0 },
  visible: {
    pathLength: 1,
    transition: { duration: 2 }
  }
};

const AnimatedSVG = () => (
  <motion.svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <motion.path
      d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80"
      variants={svgVariants}
      initial="hidden"
      animate="visible"
    />
  </motion.svg>
);

Combining framer-motion with CSS Frameworks

Using framer-motion with CSS frameworks like Tailwind CSS is seamless. Define your animations with framer-motion and style your components with Tailwind classes.

const TailwindAnimation = () => (
  <motion.div className="bg-blue-500 text-white p-5"
    whileHover={{ scale: 1.1 }}
    whileTap={{ scale: 0.9 }}
  >
    Tailwind with framer-motion
  </motion.div>
);

Summary

framer-motion is a robust library that simplifies creating complex animations in React applications. By leveraging its powerful API, you can create reusable, manageable, and scalable animation components. Whether it’s animating SVGs, handling scroll animations, or employing keyframes, framer-motion offers the tools to elevate the user experience in your web projects.

Integrating framer-motion properly into your React workflow unlocks endless possibilities for creating captivating interfaces, making your applications stand out in the crowded web landscape.

Article tags
reactanimationsframer-motionweb-developmentui
Previous article

Tooling and Libraries

Advanced Patterns with React.memo and useCallback

Next article

Debugging Techniques

Advanced Patterns with React Error Boundaries