Highlight Text on Scroll with GSAP + Elementor (Split Text Tutorial)

In this GSAP and Elementor tutorial, I’ll show you how to easily create a highlight text on scroll effect as the user scrolls down the page. The video is organized with timestamps for different use cases, so you can jump to the section that fits your project. All the code used in the tutorial is included below in the description so you can copy and use it in your own Elementor site.

Get Elementor Pro

Timestamps:

  • 0:00 Split Text Demo
  • 0:42 Single Split Text Section
  • 9:01 GSAP Mobile Controls
  • 13:17 Multiple Sections on Page

Single Split Text Section

				
					<!-- GSAP Core -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js"></script>

<!-- SplitType -->
<script src="https://cdn.jsdelivr.net/npm/split-type@0.3.4/umd/index.min.js"></script>

<script>
gsap.registerPlugin(ScrollTrigger);

// Prevent ScrollTrigger from recalculating too much on mobile viewport changes
ScrollTrigger.config({ ignoreMobileResize: true });

function initSplitText() {
  const headings = document.querySelectorAll(".text-split h2");
  if (!headings.length) return; // Exit if no headings found

  // Split the text into chars
  const splitInstance = new SplitType(headings, { types: "words, chars" });

  // Initial style
  gsap.set(splitInstance.chars, { color: "#FFFFFF61" });

  // Animate colors on scroll
  gsap.to(splitInstance.chars, {
    color: "#ffffff",
    stagger: 0.02,
    ease: "none",
    scrollTrigger: {
      trigger: ".text-split",
      start: "top 50%",
      end: "bottom 85%",
      scrub: 0.6,
      markers: true,
      invalidateOnRefresh: true // critical for iOS Chrome viewport changes
    }
  });
}

// Initialize on fonts + page load
window.addEventListener("load", () => {
  document.fonts.ready.then(() => {
    initSplitText();
    ScrollTrigger.refresh();
  });
});

// Use GSAP's built-in resize handling instead of window.resize
ScrollTrigger.addEventListener("refreshInit", () => {
  document.fonts.ready.then(() => initSplitText());
});
ScrollTrigger.addEventListener("refresh", () => {
  // optional: can reset styles if needed
});
</script>
				
			

GSAP Mobile Controls

				
					<!-- GSAP Core -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js"></script>

<!-- SplitType -->
<script src="https://cdn.jsdelivr.net/npm/split-type@0.3.4/umd/index.min.js"></script>

<script>
gsap.registerPlugin(ScrollTrigger);

ScrollTrigger.config({ ignoreMobileResize: true });

function initSplitText() {

  const headings = document.querySelectorAll(".text-split h2");
  if (!headings.length) return;

  const splitInstance = new SplitType(headings, { types: "words, chars" });

  gsap.set(splitInstance.chars, { color: "#FFFFFF61" });

  // Detect mobile
  const isMobile = window.innerWidth < 768;

  const startPoint = isMobile ? "top 70%" : "top 50%";
  const endPoint = isMobile ? "bottom 95%" : "bottom 85%";

  gsap.to(splitInstance.chars, {
    color: "#ffffff",
    stagger: 0.02,
    ease: "none",
    scrollTrigger: {
      trigger: ".text-split",
      start: startPoint,
      end: endPoint,
      scrub: 0.6,
      markers: true,
      invalidateOnRefresh: true
    }
  });
}

// Use GSAP's built-in resize handling instead of window.resize
ScrollTrigger.addEventListener("refreshInit", () => {
  document.fonts.ready.then(() => initSplitText());
});
ScrollTrigger.addEventListener("refresh", () => {
  // optional: can reset styles if needed
});
</script>
				
			

Multiple Sections on Page

				
					<!-- GSAP Core -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js"></script>

<!-- SplitType -->
<script src="https://cdn.jsdelivr.net/npm/split-type@0.3.4/umd/index.min.js"></script>

<script>
gsap.registerPlugin(ScrollTrigger);

// Prevent ScrollTrigger from recalculating too much on mobile viewport changes
ScrollTrigger.config({ ignoreMobileResize: true });

function initSplitText() {
  const sections = document.querySelectorAll(".text-split");

  if (!sections.length) return;

  sections.forEach(section => {
    const heading = section.querySelector("h2");
    if (!heading) return;

    // Split the text into chars for this section
    const splitInstance = new SplitType(heading, { types: "words, chars" });

    // Initial style
    gsap.set(splitInstance.chars, { color: "#ffffff" });

    // Animate colors on scroll for this section
    gsap.to(splitInstance.chars, {
  color: "#0275E3",
  stagger: 0.02,
  ease: "none",
  scrollTrigger: {
      trigger: section,
      start: "top 50%",
      end: "bottom 85%", 
    scrub: 0.6,
    markers:true,
    invalidateOnRefresh: true
      }
    });
  });
}

// Initialize on fonts + page load
window.addEventListener("load", () => {
  document.fonts.ready.then(() => {
    initSplitText();
    ScrollTrigger.refresh();
  });
});

// Use GSAP's built-in resize handling instead of window.resize
ScrollTrigger.addEventListener("refreshInit", () => {
  document.fonts.ready.then(() => initSplitText());
});
</script>
				
			

Free Brand Messaging Worksheet

Define Your Voice and Connect with Your Audience

More Free Resources

Let's Work Together

Big ideas start with a quick chat. Let’s talk!

Business Growth Insights Worth Opening

Practical, no-fluff insights on branding, web design, and building a stronger business. As a subscriber, you’ll also get exclusive access to our $500 referral bonus program.