Tutorials

avatar

Malik Kotb

Nov 25, 2024 / Beginner / Short

Marquee Cursor
Animated Marquee Button using GSAP

A web animation tutorial on creating a smooth marquee button effect using Next.js and GSAP. This tutorial provides a step-by-step guide to implementing a seamless scrolling text animation for buttons, perfect for enhancing interactivity and visual appeal in modern web designs.

Initializing the project

Let's start the project by setting up a Next.js app with TypeScript and utilizing the app router. Just run npx create-next-app@latest in the terminal.

We can clear out all the contents in the page.tsx, and global.css files, and add our own HTML and CSS, to begin with a clean slate in the application.

CSS Module

We begin by creating a slider container that holds the marquee text elements. Here’s the CSS:

page.tsx

1.slider {
2  position: relative;
3  white-space: nowrap;
4}
5
6.slider p {
7  position: relative;
8  margin: 0;
9  font-size: 16px;
10  font-weight: 500;
11  padding-right: 4px;
12}
13
14.slider p:nth-of-type(2) {
15  position: absolute;
16  left: 100%;
17  top: 0;
18}
19

Page Component

We’ll add the MarqueeButton component to the Home page to render the animation in the center of the screen:

page.tsx

1import MarqueeButton from "@/components/MarqueeButton/MarqueeButton";
2
3export default function Home() {
4  return (
5    <div className="h-screen w-screen flex justify-center items-center">
6      <MarqueeButton />
7    </div>
8  );
9}
10

Animating the Marquee

Next, in the MarqueeButton component, we use GSAP to animate the scrolling effect.

page.tsx

1"use client";
2import styles from "./style.module.css";
3import { useEffect, useRef } from "react";
4import gsap from "gsap";
5
6export default function MarqueeButton() {
7  const firstText = useRef(null);
8  const secondText = useRef(null);
9  const slider = useRef(null);
10
11  let xPercent = 0; // Tracks the scrolling position
12
13  useEffect(() => {
14    // Set the initial position of the second text
15    gsap.set(secondText.current, {
16      left: secondText.current.getBoundingClientRect().width,
17    });
18
19    // Start the animation loop
20    requestAnimationFrame(animate);
21  }, []);
22
23  // Animation logic for looping text
24  const animate = () => {
25    if (xPercent < -100) {
26      xPercent = 0; // Reset position for looping
27    }
28    // Move both text elements horizontally
29    gsap.set(firstText.current, { xPercent: xPercent });
30    gsap.set(secondText.current, { xPercent: xPercent });
31
32    requestAnimationFrame(animate); // Keep animating
33    xPercent -= 0.3; // Adjust speed of scrolling
34  };
35
36  return (
37    <div className={styles.main}>
38      <div ref={slider} className={styles.slider}>
39        <p ref={firstText}>View Details -</p>
40        <p ref={secondText}>View Details -</p>
41      </div>
42    </div>
43  );
44}
45

How it works

This setup creates a smooth marquee button animation where the text scrolls endlessly to the left. You can easily customize the text, speed, and styling to fit your project needs.

We should have something like this:
Wrapping up.

Quick and smooth, right?

Hope you liked the animation and learned something new!

-Malik

Things for creative devs
sent to your inbox every week