Infinite Marquee

Infinite Marquee

Infinite Marquee

  • React
  • Typescript
  • GSAP
  • ScrollTrigger Plugin
  • useGSAP Plugin
  • Tailwind CSS
components/infinite-marquee.tsx
import React, { useRef } from "react";
import gsap from "gsap";
import { SplitText } from "gsap/SplitText";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";

gsap.registerPlugin(SplitText, ScrollTrigger);

interface InfiniteMarqueeProps {
  children: React.ReactNode;
  duration?: number;
  className?: string;
}

export function InfiniteMarquee({
  children,
  duration = 10,
  className,
}: InfiniteMarqueeProps) {
  const containerRef = useRef<HTMLDivElement>(null);

  useGSAP(
    () => {
      if (!containerRef.current) return;

      const container = containerRef.current!;
      const elements = Array.from(container.children);

      if (elements.length === 0) return;

      gsap.to(elements, {
        xPercent: -100,
        duration,
        repeat: -1,
        ease: "none",
      });
    },
    { scope: containerRef, dependencies: [duration] },
  );

  return (
    <div
      ref={containerRef}
      className={`overflow-hidden w-lg flex ${className ?? ""}`.trim()}
    >
      {children}
    </div>
  );
}
<InfiniteMarquee className="w-full max-w-xl">
  <p className="p-4 whitespace-nowrap">
    FREELANCE DEVELOPER
    <span className="inline-block">
      <ArrowUpRight />
    </span>
  </p>
  <p className="p-4 whitespace-nowrap">
    FREELANCE DEVELOPER
    <span className="inline-block">
      <ArrowUpRight />
    </span>
  </p>
  <p className="p-4 whitespace-nowrap">
    FREELANCE DEVELOPER
    <span className="inline-block">
      <ArrowUpRight />
    </span>
  </p>
</InfiniteMarquee>

FREELANCE DEVELOPER

FREELANCE DEVELOPER

FREELANCE DEVELOPER