Using Greensock To Create Animations In React

explore how to create animations using gsap

Greensock Animation Platform (GSAP) is a JavaScript package that helps front-end developers create amazing, intense timeline-based animations by providing access to precise control for animation sequences as opposed to the frequently needed animation properties that come with CSS. This animation platform has ultra-high-performance and professional-level animation for the modern web, which lets developers navigate their applications in a segmental, demonstrative, and renewable style. GSAP’s scroll trigger plugin creates incredible, sensational scroll-based animations with little codes, such as toggle playback state, supports vertical and horizontal scrolling, and automatic resizing to the viewport size. We will demonstrate how GSAP integrates with React library flawlessly by fusing its features with its components to produce a dynamic landing page.

Why utilize GSAP?

The DOM elements in the animation above were created using GSAP. Attempting to recreate it with CSS animations or another library might be difficult or unlikely. According to the GSAP website:

  • GSAP is now an industry standard.
  • Most websites with awards use it.
  • Regarding JavaScript animations, Google suggests GSAP.
  • Over 11 million sites use GSAP.

The following are a few reasons why you should consider using Greensock Animation Platform (GSAP) for your animations; I recommend visiting their website to learn more about what they offer.

Unique SVG

With its potent DrawSVGPlugin and MorphSVGPlugin, GSAP offers various SVG animation effects. No matter how many points are in the starting and ending pathways, MorphSVG enables you to morph any SVG path. The way that SVG strokes are shown can be precisely controlled with DrawSVG. You don't simply have to expose a stroke from beginning to end; you can reveal it from the center and use any segment length you choose. An excellent feature for responsive designs is the ability to easily circulate an SVG detail based entirely on a percentage of its width or height.

Accessible and friendly animations

The gsap.matchMedia() allows you to input setup code into a function that executes when a media query matches, and if it does not match anymore, all GSAP animations and scroll triggers generated during that function's implementation get reverted automatically, see here to learn more. With this, customizing for mobile/desktop accessibility is outstanding.

Performance

This animation platform has amazing high professional performance across different browsers. GSAP is 20x faster than JQuery, GSAP is the fastest fully-featured scripted animation tool in the world which happens to be even faster than CSS animations and transitions in most cases, see the speed comparison. The lagSmoothing() feature makes GSAP heal from the CPU spikes that can make it lag while maintaining a perfect synchronization between all animations, click here to learn more about its performance. Performance is an outstanding characteristic, especially when it comes to mobile devices that have got slow processors, having silky-smooth animation is the trademark of any library and GSAP has got that because it outperforms old industry standards. With its speed test for head-to-head comparisons and its result of numerous optimizations made so interactive designs can be efficient, responsive, and able to run smoothly.

Community

GSAP has got a huge community that's always ready to help, its large community is one of its best features. Applauds are being given for its outstanding support and the warmth of its forums which has lots of generous developers who are ready and passionate about animation and helping others seeking answers in the community. There are over a hundred thousand posts on the forum. A lot of projects have little or no dedicated support, you would be asked to pay, and most times it's on the high side. They have an excellent Forum which is a great place to be, get connected, find answers, and grow skills by lurking around and reading discussions.

Custom easing

Custom easing is the fundamental method for altering your tweens timing. It determines how an item modifies its role at specific points. GSAP gives distinctive eases and alternatives to provide you with extra management over how your animation must behave. You can select your desired ease settings with the help of the ease visualizer that is provided, see the image below:

Take the code block below, for example:

export const animateMenuOpen = (element1, element2) => {
  gsap.from([element1, element2], {
    duration: 0.7,
    height: 0,
    transformOrigin: "right top",
    skewY: 2,
    ease: "power4.inOut",
    stagger: {
      amount: 0.2,
    },
  });
};
export const animateMenuClose = (element1, element2) => {
  gsap.to([element1, element2], {
    duration: 0.8,
    height: 0,
    ease: "power4.inOut",
    stagger: {
      amount: 0.07,
    },
  });
};

Now, the ease function used for both animateMenuOpen and animateMenuClose is power4.inOut. Our ease function applies a power curve to the animation, meaning that it starts slowly, accelerates quickly in the middle, and then decelerates smoothly toward the end. The inOut part of the function indicates that it is meant for the entrance and exit animations, making it have a consistent easing effect for both. You can also create a custom easing function, which allows you to define your curve, this can be useful if you want to create a unique easing effect that is not available in the predefined easing functions.

Scroll-driven effects

Scroll trigger is a plugin in GSAP that permits us to cause scroll primarily based totally on animations, like withinside the case of skewing the picture while the web page scrolls. Animation on a scroll is the effect of loading and scrolling website pages. The scroll trigger plugin on the GSAP website creates brilliant scroll-based animations. This plugin is highly unrivaled in the aspects of its features and usage. With the scroll trigger plugin, you can perform the following:

  • Toggle the playback state.
  • Pin an element in a place, making it appear immune to scroll changes while the scroll trigger is active. Which helps keep your animation in view during the scroll.
  • The scroll trigger allows for vertical and horizontal scrolling and keeps track of its velocity.
  • The scroll trigger plugin has an automatic resizing feature for viewport size changes and can use function-based start or end values to run custom logic or tap in on fancy responsive CSS changes. For a better understanding of how to use the scroll trigger plugin, see the documentation.

Installation and Setup of GSAP

For npm installation of GSAP, run the following code block below in your terminal;

npm install gsap

For yarn installation of Gsap, run the code block below;

yarn add gsap

After installing GSAP, navigate to your package.json file and see that it has been installed just like the image below:

Creating our Animated Landing Page using GSAP

Above is our finished project, We’ll break the process of our landing page into components, so it will be easy to understand. We'll discuss how to use the component in the sub-section below.

Components

The following are the components that we will use to create our landing page: Animations.js: This has all animation methods, Image.js: import gallery images, Menu.js: This contains the menu toggle functionality, Header.js: Has navigation links.

To start, we'll create a component folder in the src directory and create an animations.js file, then input the following code block below into the file.

import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
// Define a function that animates the introduction of a given element
export const animateText = (element) => {
  // Use GSAP to create an animation timeline
  gsap.from(element, {
    xPercent: -20,
    opacity: 0,
    stagger: 0.2,
    duration: 2,
    scale: -1,
    ease: "back",
  });
};

The code block above imports the GSAP library and the scroll trigger plugin from GSAP. The above code exports a function called animateText that animates the introduction of a given element on a web page using the GSAP animation library. The function takes one argument element that should refer to a DOM element that needs to be animated. Inside the function, gsap.from method is used to create an animation timeline that animates the element from a starting position of -20% on the x-axis and 0% opacity to its final position with a staggered delay of 0.2 seconds between each animation step. The animation has a duration of 2 seconds and uses the "back" ease function to add a bounce effect. The scale property is set to -1. Let's navigate to our app.js file and include the code block below:

import { useRef, useEffect } from "react";
import { animateText } from "./components/Animations";
function Home() {
  const introRef = useRef(null);
  useEffect(() => {
    animateText(introRef.current);
  }, []);
  return (
    <div className="container">
      <div className="wrapper">
        <div className="hero__img"></div>
        <h5 className="intro" ref={introRef}>
          <b>GOLDEN CUISINE</b>, Golden cuisine is an innovative, exceptional,
          online e-commerce platform that always prioritizes customer
          satisfaction.
        </h5>
      </div>
    </div>
  );
}

The code block above explains that we used the useRef hook from the React library to create a reference to a DOM element. This reference is stored in the introRef variable, which is used as a prop to the <h5> element to allow access to its DOM node. The useEffect hook calls the animateText function when the component is mounted. The animateText function defined in another module takes the introRef.current value as an argument, which is the current DOM node referenced. This causes the text in the header to animate when the component is first rendered. The JSX markup contains a container div with a wrapper class, an empty div with a hero__img class, and an <h5> element with an intro class that includes the animated text. The text itself; describes a fictional online e-commerce platform called "Golden Cuisine" that prioritizes customer satisfaction.

Creating our menu

Our menu does not have a drop-down when clicked. To make it work, navigate to the header.js component, and input the code block below:

import React, { useState, useEffect, useRef } from "react";
import { withRouter, Link, useHistory } from "react-router-dom";
import Menu from "./Menu";
const Header = () => {
  const history = useHistory();
  let logoRef = useRef(null);
  const [state, setState] = useState({
    initial: false,
    clicked: null,
    menuName: "Menu",
  });
  const [disabled, setDisabled] = useState(false);
  useEffect(() => {
    animateText(logoRef);
    history.listen(() => {
      setState({ clicked: false, menuName: "Menu" });
    });
  }, [history]);
  const toggleMenu = () => {
    disableMenu();
    if (state.initial === false) {
      setState({
        initial: null,
        clicked: true,
        menuName: "Close",
      });
    } else if (state.clicked === true) {
      setState({
        clicked: !state.clicked,
        menuName: "Menu",
      });
    } else if (state.clicked === false) {
      setState({
        clicked: !state.clicked,
        menuName: "Close",
      });
    }
  };
  const disableMenu = () => {
    setDisabled(!disabled);
    setTimeout(() => {
      setDisabled(false);
    }, 1200);
  };
  return (
    <header>
      <div className="container">
        <div className="wrapper">
          <div className="inner-header">
            <div className="logo" ref={(el) => (logoRef = el)}>
              <Link to="/">GOLDEN CUISINE.</Link>
            </div>
            <div className="menu">
              <button disabled={disabled} onClick={toggleMenu}>
                {state.menuName}
              </button>
            </div>
          </div>
        </div>
      </div>
      <Menu state={state} />
    </header>
  );
};
export default withRouter;

In the above code block, we defined our menu and button state, the header component uses the useHistory hook from the react-router-dom library to access the current page history. It also uses the useRef and useState hooks from the React library to create a reference to a logo element and manage the state of the menu and menu button. The useEffect hook is used to animate the logo using the animateText function and reset the menu state when the page changes. The toggle menu function is called when the menu button is clicked, and it disables the button, updates the menu state based on its current state, and then enables the button again after a timeout. The JSX markup renders a header element with a container div, a wrapper div, an inner-header div, a logo div with a link component, a menu div with a button component, and a menu component that displays the drop-down menu based on the state passed as a prop. Now let’s head over to our animations file to write out the methods that make our menu drop-down before creating the actual menu component:

// Function to open menu with animation
export const animateMenuOpen = (element1, element2) => {
  gsap.from([element1, element2], {
    duration: 0.7,
    height: 0,
    transformOrigin: "right top",
    skewY: 2,
    ease: "power4.inOut",
    stagger: {
      amount: 0.2,
    },
  });
};
// Function to close menu with animation
export const animateMenuClose = (element1, element2) => {
  gsap.to([element1, element2], {
    duration: 0.8,
    height: 0,
    ease: "power4.inOut",
    stagger: {
      amount: 0.07,
    },
  });
};

The code block above contains two functions that utilize the GSAP library to animate the opening and closing of a menu. The animateMenuOpen function takes two parameters, element1, and element2 which are the menu elements being animated. This function animates the height and skew of the elements, creating a sliding and skewing effect as the menu opens. The duration of the animation is 0.7 seconds, and the ease function used is "power4.inOut". The stagger option specifies a delay between animations of the two elements. The animateMenuClose function is similar to animateMenuOpen but animates the elements to a height of 0 to hide the menu. The duration of this animation is 0.8 seconds, and the ease function is the same as animateMenuOpen. The stagger option also specifies a delay between the animations of the two elements. Overall, these functions provide an easy and efficient way to open and close a menu with smooth animation. To utilize these features, head over to your components directory, create a menu.js file, and then paste the following code block below:

import React, { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { Link } from "react-router-dom";
import {
  animateMenuOpen,
  animateMenuClose,
  animateText,
} from "./Animations.js";
const Menu = ({ state }) => {
  // Create refs for DOM elements
  const menuWrapperRef = useRef(null);
  const show1Ref = useRef(null);
  const show2Ref = useRef(null);
  const infoRef = useRef(null);
  useEffect(() => {
    if (state.clicked === false) {
      // Close the menu
      animateMenuClose(show2Ref, show1Ref);
      // Set menuWrapper to display none
      gsap.to(menuWrapperRef, { duration: 1, CSS: { display: "none" } });
    } else if (
      state.clicked === true ||
      (state.clicked === true && state.initial === null)
    ) {
      // Open the menu
      gsap.to(menuWrapperRef, { duration: 0, CSS: { display: "block" } });
      gsap.to([show1Ref, show2Ref], {
        duration: 0,
        opacity: 1,
        height: "100%",
      });
      animateMenuOpen(show1Ref, show2Ref);
      animateText(infoRef);
    }
  }, [state]);
  return (
    <div ref={menuWrapperRef} className="hamburger-menu">
      <div ref={show1Ref} className="menu-secondary-background-color"></div>
      <div ref={show2Ref} className="menu-layer">
        <div className="container">
          <div className="wrapper">
            <div className="menu-links">
              <nav>
                <ul>
                  <li>
                    <Link ref={(el) => (line1 = el)} to="/about-us">
                      About
                    </Link>
                  </li>
                  <li>
                    <Link ref={(el) => (line2 = el)} to="/gallery">
                      Gallery
                    </Link>
                  </li>
                  <li>
                    <Link ref={(el) => (line3 = el)} to="/contact-us">
                      Contact us
                    </Link>
                  </li>
                </ul>
              </nav>
              <div ref={infoRef} className="info">
                <h3>Our Vision</h3>
                <p>
                  At Golden cuisine, we offer personal exotic cuisine with an
                  innovative gastronomic take on traditional cooking methods and
                  the legacy of our shared food heritage. Moreover, we regard it
                  as a personal challenge to help bring about distinctive
                  flavors and particular regional characters that brighten up
                  the world.
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};
export default Menu;

In our code block above the component uses the useRef hook from React to create references to several DOM elements, including the menu wrapper, two show elements, and an info element. These elements will be animated using the GSAP library, which is imported at the top of the code block. This component also uses the useEffect hook to handle changes to the state prop. A state prop is an object that contains a clicked property and an initial property. When clicked is false, the menu should be closed, and when clicked is true, the menu should be opened. If the initial is null, it means the menu has not yet been opened or closed. When the menu is closed, the animateMenuClose function is called with the show1Ref and, show2Ref parameters. This function uses GSAP to animate these elements and hide them. When the menu is opened, several GSAP animations are used to show the menu. First, the menuWrapperRefis set to display: block then, the show1Ref and, show2Ref elements are set to opacity: 1 and height: '100%'Finally, the animateMenuOpenand animateTextfunctions are called to animate the show1Ref show2Refand infoRef elements. The return statement contains the HTML for the hamburger menu. It includes the menuWrapperRef show1Ref show2Ref and infoRef elements, as well as several nested elements that contain links to different pages. The link component is imported from React-router. If all these are done appropriately and accordingly, then you should have the same image below, which is our animated menu:

Next, we will be applying the skew animation to our gallery, GSAP has a plugin called scroll trigger which enables us to trigger scroll-related animations, in our case, it will be skewing the images while the page keeps scrolling. Below is our gallery without the animation:

Now, to apply the skew animation to our gallery, let's head over to our animations.js file and modify it with the code block below:

// This function skews an element based on the user's scrolling speed using the ScrollTrigger plugin.
export const skewGallery = (element) => {
  gsap.registerPlugin(ScrollTrigger);
  gsap.set(element, { transformOrigin: "right center", force3D: true });
  // Define a function to clamp the skew value between -20 and 20 degrees.
  let clamp = gsap.utils.clamp(-20, 20);
  ScrollTrigger.create({
    trigger: element,
    onUpdate: (self) => {
      const velocity = clamp(Math.round(self.getVelocity() / 300));
      // Tween the skew of the element to the new value over 0.8 seconds.
      gsap.to(element, {
        skew: 0,
        skewY: velocity,
        ease: "power3",
        duration: 0.8,
      });
    },
  });
};

The code block above explains the skew gallery function which uses the GSAP animation library to skew our gallery element based on the user's scrolling velocity. First, we register the scroll trigger plugin provided by GSAP. Then, we use gsap.set() to set the transform origin of the element to the right center, which improves the performance of the animation by enabling hardware acceleration. We define a function called clamp that limits the skew angle to a range of -20 to 20 degrees. This ensures that the skew effect doesn't become too extreme or distracting. We then create a new scroll trigger instance that triggers when our gallery element comes into view. On each update, we calculate the scrolling velocity of the user, which determines the vertical skew angle applied to the element. We use the gsap.utils.clamp() method to ensure that the skew angle doesn't exceed the range defined by the clamp function. Finally, we use the gsap.to() method to apply the skew animation to the element. The skew property is set to 0 to maintain a consistent horizontal skew angle, while the skewY property is set to the clamped scrolling velocity value. We also specify a duration of 0.8 seconds and an ease function of power3 to control the speed and smoothness of the animation. Now, to call this function into our app.js file, input the following code block you see below:

import { skewGallery } from "./components/Animations";
function Gallery() {
  let skewImage = useRef(null);
  useEffect(() => {
    skewGallery(skewImage);
  }, []);
  return (
    <div ref={(el) => (skewImage = el)}>
      <Image />
    </div>
  );
}

In our code block above we imported our skew gallery from our module /components/Animations The component renders an image inside a div element and applies the skew gallery function to make a skewing animation effect. The useRef hook is used to declare a variable called skewImage which is initialized with a null value. The useEffect hook calls the skew gallery function once after the component is mounted, through the reference, to skewImage as an argument. This code creates our gallery component that applies a skewing animation effect to our image using the skew gallery function. The component uses the useRef and useEffect hooks to create a reference to the div element and call the skew gallery function after the component is mounted. Below is what our Gallery looks like now:

If everything is done accordingly, your project should already be up and running.

Conclusion

We have only explored what I will call the tip of the iceberg of what GSAP can do, there isn’t any limit to what you can do with GSAP when it comes to animation. Visit their official website to gain more knowledge on how to use their methods and plugins and more wonderful things GSAP has to offer. Check out GreenSock’s CodePen, some demos might inspire you.

Continue Learning

Discover more articles on similar topics