Setting up GSAP Animations on NextJS 13
Start creating beautiful web animations with GSAP and NextJS 13
I've used various React animation libraries such as Framer Motion, React Spring and others! However, GSAP (GreenSock Animation Platform) has proven itself to be my favorite JavaScript/React animation library repeatedly. Originally released in 2006, GSAP has amassed a reputation for being a powerful tool for creating unique web experiences.
Examples of websites I created using the power of GSAP + NextJS:
Exquisite Wood Floors - every animation was achieved with GSAP, my favorite animation is the wood tile page transitions.
Finnish Interiors - Loading screen animation & every animation was achieved with GSAP
Blockhead Digital - this is my freelance digital growth company - was able to achieve a loading screen animation and animate a ThreeJS object using GSAP.
Check out what other developers are creating with GSAP. These animations are insane, I spent hours scrolling - https://greensock.com/showcase/
In this tutorial, we will show you how to set up GSAP animations on NextJS 13, a popular framework for building server-rendered React applications. By the end of this guide, you'll be able to create smooth, performant animations that will take your NextJS projects to the next level.
Setting up GSAP on NextJS
To start, we're gonna create our NextJS 13 project using the following command:
npx create-next-app@latest project-name
Change project-name
to whatever you feel appropriate - I used gsap-demo
. You're then going to see a few prompts asking you for your project preferences, select whatever settings you see fit. I've opted for the following settings:
✔ Would you like to use TypeScript with this project? … No
✔ Would you like to use ESLint with this project? … Yes
✔ Would you like to use `src/` directory with this project? … No
✔ Would you like to use experimental `app/` directory with this project? › No
✔ What import alias would you like configured? … @/*
I went ahead and installed TailwindCSS for styling because it's the best thing ever. Follow this guide to install TailwindCSS in your project.
I also removed the default styling in global.css
and elements in index.js
page to get a blank page:
export default function Home() {
return (
<>
<main>
<div>Hello</div>
</main>
</>
);
}
Now run the following command to install GSAP in your project:
npm i gsap
You now have GSAP installed in your project - you're now ready to create beautiful animations.
Basic Animations
I created a simple red cube which we'll animate throughout this article. To start we need to import gsap
into our project. I imported it into index.js
.
import gsap from "gsap";
export default function Home() {
return (
<>
<main className="h-screen w-screen flex justify-center items-center">
<div className="w-20 h-20 bg-rose-600"></div>
</main>
</>
);
}
According to information found on the Greensock website (greensock.com), accessing DOM nodes and using Refs, in combination with the useLayoutEffect hook, is the recommended method for targeting elements and running GSAP animations in React/NextJS applications. However, I haven't had any issue with the useEffect hook to run animations - find whichever works best for you.
gsap
comes with various useful methods for animating elements. We'll be using the to()
method.
The most common type of animation is a to() tween because it allows you to define the destination values (and most people think in terms of animating to certain values):
// rotate and move DOM node ref element // ("x" is a shortcut for a translateX() transform) // over the course of 1 second. gsap.to(boxRef.current, {rotation: 27, x: 100, duration: 1});
With useRef
, useLayoutEffect
Hook and gsap.to()
in mind, here's an example of a simple GSAP animation in NextJS 13:
import { useRef, useLayoutEffect } from "react";
import gsap from "gsap";
export default function Home() {
const boxRef = useRef();
//useLayoutEffect ensures that elements are rendered and ready to be animated
useLayoutEffect(() => {
// Refs allow you to access DOM nodes
console.log(boxRef); // { current: div.box }
// then we can animate them like so...
gsap.to(boxRef.current, {
// rotate 360
rotation: "+=360",
//repeat forever
repeat: Infinity,
});
}, []);
return (
<>
<main className="h-screen w-screen flex justify-center items-center">
<div ref={boxRef} className="w-20 h-20 bg-rose-600"></div>
</main>
</>
);
}
🎉 Congratulations! 🎉 You have created your first GSAP animation on NextJS 13!
Feel free to play around with the values and different properties - you can animate any CSS property you can think of! Test out gsap.from()
and gsap.fromTo()
- you should be able to guess what kind of animations you can achieve with those methods.
Animating multiple elements
What if you have multiple elements you want to animate? It would be annoying if we had to create a Ref for every single element. This is where gsap.context()
comes in!
gsap.context() provides two incredibly useful features for React developers, the option of using scoped selectors and more critically - animation cleanup.
To start, all we need to do is provide gsap.context()
a scope Ref - I usually place it on the parent container of the component I'm animating. This allows us to use selector text (like ".my-class"
or "#my-id"
) to animate descendent elements. We don't need Refs for every element - we just need to provide an id
, classname
or other attributes to identify our elements, they're similar to CSS selectors.
let ctx = gsap.context(() => {
//animations
gsap.to("#apple", { // animate elements w/ id="apple"
y: 10,
})
gsap.to("#orange", { // animate elements w/ id="orange"
x: 10,
})
}, scopeRef) //parent scope
Cleaning Up
useLayoutEffect()
provides us with a cleanup function that we can use to kill animations. Proper animation cleanup is crucial to avoid unexpected behaviour with React 18's strict mode. This pattern follows React's best practices.
gsap.context
makes cleanup nice and simple, all GSAP animations and ScrollTriggers created within the function get collected up so that you can easilyrevert()
ALL of them at once.We can also use this cleanup function to kill anything else that could cause a memory leak, like an event listener.
I've added two boxes to my previous example, added the Ref to the parent container and added an id
attribute to all three of the boxes:
import { useRef, useLayoutEffect } from "react";
import gsap from "gsap";
export default function Home() {
const ref = useRef();
useLayoutEffect(() => {
let ctx = gsap.context(() => {
gsap.to("#box", {
rotation: "+=360",
repeat: Infinity,
});
gsap.to("#box1", {
y: -100,
yoyo: true, // animates from start -> end -> start
repeat: Infinity,
});
gsap.to("#box2", {
scale: "1.5",
yoyo: true,
repeat: Infinity,
});
}, ref); //scope
return () => ctx.revert(); // cleanup
}, []);
return (
<>
<main
ref={ref}
className="h-screen w-screen flex justify-center items-center gap-10"
>
<div id="box" className="w-20 h-20 bg-rose-600"></div>
<div id="box1" className="w-20 h-20 bg-rose-600"></div>
<div id="box2" className="w-20 h-20 bg-rose-600"></div>
</main>
</>
);
}
Conclusion
Setting up GSAP on NextJS is straightforward as installing any other package - the implementation can be a little tricky, but now that you have your first animation up & running, you can start your journey into creating more advanced animations, like scroll-based animations using ScrollTrigger, complex sequence animations using Timeline's, and more!
Here are a few resources to help with your GSAP journey:
GSAP Forums - You can find anything (bugs, animations, errors) you need about GSAP here
Here's the source code for this project.
P.S. Thank you for reading my first blog post - this will be the first of many.
Did you find this article valuable?
Support Luke Vakasisikakala by becoming a sponsor. Any amount is appreciated!