How To Use Framer Motion With React, TypeScript and StyledComponents?

Share

As you already know, Framer Motion is a really powerful animation library for React.

Now it’s time to start using it.

Here are some basics.

How to start with Framer Motion

To start with Framer Motion for React you have to install the right package:

npm

npm install framer-motion --save

yarn

 yarn add framer-motion

Next step is to import posed from react-pose in the file that we want to use it:

 import { motion } from 'framer-motion';

And now the fun begins!

We can animate any HTML or SVG elements. We can use Styled Components, CSS Modules, SCSS, CSS or whatever we want to add styles. There are two ways of creating posed components:

1. When you’re using classNames:

import motion to the file that you want to use it in like this:

import { motion } from 'framer-motion';

add HTML element after motion. and put it inside angle brackets, just like it was a regular HTML tag or component, add needed className:

<motion.div className="box" />

As a result, it will create a div with a .box class name. You can use it to add styles to this element. Animation properties will be added via variant and animate config, so you don’t have to take care of them in CSS.

2. When you’re using StyledComponents:

the first step is the same as 1.a., but you also have to import styled to use styled-components:

import { motion } from 'framer-motion';
import styled from 'styled-components';

create StyledComponent with motion element as a tag:

const BoxStyled = styled(motion.div)`
    display: flex;
`;

use it the same way as in 1.b. This time you don’t add className:

return <BoxStyled />;

Animate

To prepare the animation we have to use the animate property.

It should be added to the motion component (in this case it will be BoxStyled).

To make a simple animation we can pass some attributes directly into the animate prop like this:

return <BoxStyled animate={{ scale: 0.5 }} />;

It will start when the component will be rendered on the page.

You can wonder what happens with animation transition.

Well, Motion will create an appropriate animation for a snappy transition based on the types of value being animated.

“For instance, physical properties like x or scale will be animated via a spring simulation. Whereas values like opacity or color will be animated with a tween.”

It can be passed as an attribute inside the animate property or as a separate transition property.

If no transition will be set inside animate, then Motion will take its config from transition prop:

return (
   <BoxStyled 
     animate={{ scale: 0.5 }} 
     transition={{ duration: 2 }} 
   />
);

And that’s it. You’ve created your first Motion animation!

Variants

To make more advanced animation that can be adjusted based on changes inside a component, we need to prepare some variants – animation states that our component will be in, like open and closed, visible and hidden, etc.

Let’s make it step by step:

Step 1

Prepare variant config object – you can name it whatever you want, you will later use this name inside StyledComponent. Inside you should add animation states names like visible and hidden:

const variants = {
  visible: {},
  hidden: {}
};

Step 2

When you have your states declared, it’s time to add some animation properties. In this example, we want to show and hide the element, so those are the attributes that we want to animate:

const variants = {
  visible: { opacity: 1, transition: { duration: 3 } },
  hidden: { opacity: 0 }
};

Step 3

Add variant config to StyledComponent as an attribute like this:

const BoxStyled = styled(motion.div).attrs(() => ({
  initial: "hidden",
  variants}))`
    display: flex;
`;

You can set initial variant if you need your animation to start from it (it’s not necessary)

Step 4

Set needed animation variant inside a Component:

return <BoxStyled animate=”visible” />;

You can also change the animation dynamically, for example when the state changes:

import * as React from "react";
import { useState } from "react";

import { BoxStyled } from "./styles";

const Box: React.FC = () => {
  const [isVisible, setIsVisible] = useState<boolean>(false);

  return (
    <>
      <button
        type="button"
        onClick={() => setIsVisible(prevState => !prevState)}
      >
        Click here to make content visible
      </button>
      <BoxStyled 
        animate={isVisible ? "visible" : "hidden"}
      >
        I’m visible!
      </BoxStyled>
    </>
  );
};

export default Box;

And voilà! Next animation ready!

This is how it should be looking like:

What about the children?!

Well, since you asked:

“If a motion component has children, changes in variant will flow down through the component hierarchy. These changes in variant will flow down until a child component defines its own animate property.”

If you don’t want children to inherit animation from their parent you can add inherit prop and set it to false.

Animation set on children will start simultaneously with parent animation.

If we want the parent to orchestrate the execution of child animations we can use some extra transition props that we gain access to when using variants:

  • when
  • delayChildren
  • staggerChildren
const variants = {
  visible: { 
    opacity: 1, 
    transition: {
      when: "beforeChildren",
      staggerChildren: 0.3,
    }
  },
  hidden: { 
    opacity: 0, 
    transition: {
      when: "afterChildren",
    }
  }
};

Here’s a live example:

There are many cool properties that you can use. You can find all of them in the documentation.

AnimatePresence

If you’re working on react projects, then you know that sometimes we want to render a component or its part and sometimes we don’t or we just shouldn’t.

It creates a small problem with animations because we can’t add any effect on an element that just disappears.

Motion provides a component called AnimatePresence that helps us in those situations. It’s really easy to use and provides some hooks that we can use inside its children.

import { motion, AnimatePresence } from "framer-motion"

export const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible && (
      <StyledBox
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      />
    )}
  </AnimatePresence>
)

In this example, our component is rendered only when prop isVisible is set to true.

To use this component properly, we have to add exit animation.

It will be used when component will be unmounting itself. AnimatePresence should always be present in the DOM.

Events and gestures

As already said at the beginning – this library offers more advanced listeners, extends the basic set of event listeners provided by React. We can use:

  • hover – detects when a pointer hovers over or leaves a component
    • whileHover
    • onHoverStart(event, info)
    • onHoverEnd(event, info)
  • tap – detects when a pointer presses down and releases on the same component
    • whileTap
    • onTap(event, info)
    • onTapStart(event, info)
    • onTapCancel(event, info)
  • pan – recognizes when a pointer presses down on a component and moves further than 3 pixels
    • onPan(event, info)
    • onPanStart(event, info)
    • onPanEnd(event, info)
  • drag – follows the rules of the pan gesture but applies pointer movement to the x and/or y-axis of the component
    • drag
    • dragConstraints
    • dragElastic
    • dragMomentum
    • dragTransition
    • dragPropagation
    • dragControls
    • onDrag(event, info)
    • onDragStart(event, info)
    • onDragEnd(event, info)
    • onDirectionLock(axis)

You can read more about them here.

It gives us many possibilities. We can even add a separate animation on elements on event start, on event end and while the event is active. It’s not possible with CSS only.

Here’s a live example with a really simple animation:

SVGs

There is also the ability to have some fun with SVG files. We can animate all elements just as usual. Motion provides some additional properties for paths:

  • pathLength
  • pathSpacing
  • pathOffset

All of those can be set as a value between 0 and 1.

“A note on SVG filters.
The while helper properties won’t work on SVG filter components, as these elements don’t have a physical presence and therefore don’t receive events. To respond to gestures, you need to introduce React state to the component and attach listeners to the physical element.”

So there are also some limitations. I’ve prepared a really simple animation using SVG below.

It is created with pathLength.

So, what now?

I believe that Motion gives us many possibilities and makes our life easier in many cases.

It’s definitely worth learning.

You can start from those simple animations provided in this article and then create something on your own.

There are also many examples on the Framer Motion documentation page. Maybe you will get inspired by some of them.

Want to use Framer Motion in your project?

Comments
Leave a Reply

View Comments (0)...

Related articles:

How to Efficiently Build a Cryptocurrency News Portal in 2021 – Part I

Pros and Cons of NextJS in 2021