Animations with Framer Motion

Here are some examples of simple animations with Framer Motion. Specifically how to animate the path of an svg.

npm install framer-motion
import React from "react";
import { motion } from "framer-motion";

const iconVariants = {
  hidden: {
    pathLength: 0,
    stroke: "rgba(24, 56, 143, 0)",
  },
  visible: {
    pathLength: 1,
    stroke: "rgba(24, 56, 143, 1)",
  },
};

const Logo = () => {
  return (
    <svg height="48px" viewBox="0 0 13 15">
      <motion.path
        fill="transparent"
        d="M0 14V1l6.5 6.5L13 1v13l-3.25-3.25L6.5 14l-3.25-3.25z"
        //
        initial="hidden"
        animate="visible"
        variants={iconVariants}
      />
    </svg>
  );
};
export default Logo;

The delay and duration can also be changed. I set the duration to 1.5 since the default is quite short.

...
variants={iconVariants}
transition={{
    delay: 0.3,
    duration: 1.5,
}}

To only start animating when it appears in the viewport, we can manually start the animation with the help of the Intersection Observer API.

npm install react-intersection-observer
import React, { useEffect } from "react";
import { useInView } from "react-intersection-observer";
import { motion, useAnimation } from "framer-motion";

const Logo = (props) => {
    const controls = useAnimation();
    const [ref, inView] = useInView();

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


    return (
        <svg>
            <motion.path
                // we pass the ref to attach the intersection observer
                ref={ref}
                variants={{
                    "hidden": { ... },
                    "visible": { ... }
                }}

                initial="hidden"
                // animate="visible"
                animate={controls}
                />

        </svg>
    )
}
export default Logos

Instead of giving animate the string "visible" we pass it the controls. And when inView changes, the animation is started with controls.start("visible");.


Framer Motion is quite powerful but still easy to use. The attributes whileHover and whileTap for example are great to animate a button.

import React from "react";
import Link from "next/link";
import { motion } from "framer-motion";

const ButtonLink = ({ href, className = "", children, ...rest }) => {
  className = `bg-yellow-500 hover:bg-yellow-600 text-white transition-colors py-3 px-5 rounded-md text-center ${className}`;

  return (
    <Link href={href} passHref>
      <motion.a
        whileHover={{ scale: 1.1 }}
        whileTap={{ scale: 0.9 }}
        className={className}
        {...rest}
      >
        {children}
      </motion.a>
    </Link>
  );
};