Tutorials
Malik Kotb
Nov 25, 2024 / Beginner / Short
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.
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.
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
.slider
: Makes the container a scrolling line by using white-space: nowrap..slider p:nth-of-type(2)
: Places the second text directly after the first text, off-screen, creating a continuous scrolling effect.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
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
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.