Text animations can make a website more engaging by revealing content as visitors scroll through the page. These effects can draw attention to headings, section titles, and other important content, creating a more dynamic browsing experience.

In this tutorial, you'll learn how to animate text on scroll with SplitFX, a JavaScript text animation plugin.

SplitFX simplifies the process, allowing you to create these effects in just 3 steps without manually splitting the text or writing the scroll detection and animation logic yourself.

What Is a Text Animation on Scroll?

A text animation on scroll is an animation triggered when text becomes visible in the viewport while a user scrolls through a webpage.

For example, you can make a heading:

  • Fade into view from the bottom
  • Reveal one character at a time
  • Animate one word after another
  • Rotate or zoom into view
  • Use a staggered animation where each character starts slightly after the previous one

Instead of animating the entire heading at once, a text animation library can split the text into smaller units such as characters and words and animate those units individually.

What is SplitFX and Why Use it for Scroll Text Animations?

SplitFX is a JavaScript text animation plugin that splits the text of HTML elements into individual units (characters and words) and animates them.

Creating scroll-triggered text animations with SplitFX saves you from manually splitting text, creating individual animations, and handling scroll detection yourself. SplitFX takes care of these steps while giving you control over how and when the text is animated.

Animate text by character or word, choose from different built-in animations, and customize them to match your design. With SplitFX, you can add engaging scroll text animations without building the animation logic from scratch.

Install SplitFX

To get started with SplitFX, add it to your project.

Using npm

npm install @tanglat/splitfx 

Then import it into your project:

import SplitFX from "@tanglat/splitfx"; 

Using CDN

You can also load SplitFX directly from a CDN. This exposes SplitFX as a global variable:

<script src="https://cdn.jsdelivr.net/npm/@tanglat/splitfx@1/dist/umd/splitfx.min.js"></script> 

Create a SplitFX instance

Create a SplitFX instance and define how the text should be animated. The following example uses character-based animation for the entrance and disables the exit animation.

const textAnimator = new SplitFX({ "in": { "mode": "chars", "includeSpaces": false, "animation": "wipeTop", "duration": 700, "easing": "ease", "stagger": 70, "staggerDir": "forward", "delay": 0 }, "out": { "mode": "words", "duration": 0, "stagger": 0 } }); 

Find and Create the Text Animation That Fits Your Needs

Take a look at the different ways you can build, customize, and explore text animations with SplitFX.

Find All Available Options

Find all available SplitFX options, supported values, default settings, and descriptions in the Options Reference.

Explore SplitFX Text Animation Demos

The SplitFX Demos page features a variety of text animations with different configurations. Explore the examples, find an animation you like, and copy its configuration and use it in your SplitFX instance.

Create and Customize Animations with SplitFX Studio

For a more interactive way to experiment with different configurations, use SplitFX Studio. It lets you create, customize, and preview text animations by changing the animation options. Once you're happy with the result, you can copy and use the configuration in your project.

Animate Text on Scroll with animateOnScroll()

Use animateOnScroll() to trigger the configured SplitFX animation when an element enters the viewport.

The method follows this syntax:

textAnimator.animateOnScroll(element, options); 
  • element is the HTML element whose text you want to animate.
  • options is an optional object that lets you control whether the animation repeats, configure the IntersectionObserver, and specify a different trigger element.

Start with an HTML heading:

<h2 id="headline"> Animate this text when it enters the viewport </h2> 

Then select the element and call animateOnScroll():

const headline = document.getElementById("headline"); textAnimator.animateOnScroll(headline); 

Repeat or Run the Animation Only Once

By default, repeat is set to true, allowing the animation to run each time the element enters and leaves the viewport.

To prevent the animation from repeating, set repeat to false:

textAnimator.animateOnScroll(headline, { repeat: false }); 

This is useful when you want a heading to animate the first time it enters the viewport without replaying the animation as the visitor scrolls back and forth.

Animate One Element When Another Enters the Viewport

Sometimes the element containing the text is not the element you want to use as the trigger.

SplitFX allows you to separate the target element from the trigger element.

For example, suppose you have a card:

<article class="card"> <h2 class="card-title">A heading inside the card</h2> <p>Card content...</p> </article> 

You may want the title animation to start when the entire card enters the viewport rather than when only the heading becomes visible.

You can do that with the trigger option:

const card = document.querySelector(".card"); const title = document.querySelector(".card-title"); const textAnimator = new SplitFX({ //... }); textAnimator.animateOnScroll(title, { trigger: card }); 

In this example, title is the text being animated, while card determines when the scroll animation is triggered.

Control When the Animation Triggers

The observerOptions option lets you customize how SplitFX detects when an element enters or leaves the viewport. It accepts options provided by the Intersection Observer API, including threshold, root, and rootMargin.

The Intersection Observer API is a built-in JavaScript Web API provided by the browser, not part of SplitFX. SplitFX uses it internally to detect element visibility. For a complete explanation of how it works and its available options, see the MDN documentation.

Set the Visibility Threshold

The threshold option accepts a number between 0 and 1, or an array of such values. It determines how much of an element must intersect the viewport before the animation is triggered. By default, it is 0, so the animation can trigger as soon as the element starts entering the viewport.

For example, set threshold to 0.5 to trigger the animation when 50% of the element is visible within the viewport.

textAnimator.animateOnScroll(headline, { observerOptions: { threshold: 0.5 } }); 

Adjust the Root Margin

The rootMargin option expands or shrinks the observer's viewport boundaries. This lets you trigger an animation before an element reaches the visible viewport or delay it until the element moves further into view.

For example, a positive bottom margin of 100px extends the observation area below the viewport, allowing the animation to trigger earlier:

textAnimator.animateOnScroll(headline, { observerOptions: { rootMargin: "0px 0px 100px 0px" } }); 

The values follow the order top, right, bottom, and left, just like CSS margins. Positive values expand the observation area, while negative values shrink it. For example, "0px 0px -100px 0px" reduces the bottom boundary, causing the element to enter the observation area later.

Animate Text Inside a Scrollable Container

The viewport isn't always the scrolling area.

The root option specifies the element used as the viewport for detecting visibility. By default, it is null, which means the browser viewport is used.

If the target is inside a scrollable container and you want the animation to respond to that container instead of the browser viewport, pass the container element as root:

const scrollContainer = document.getElementById("scroll-container"); textAnimator.animateOnScroll(headline, { observerOptions: { root: scrollContainer } }); 

The root element must contain the target element. This option is useful when your content scrolls inside a panel or another scrollable area rather than the page itself.

Animate Multiple Headings on Scroll

To animate multiple headings with SplitFX, call animateOnScroll() for each heading. You can select the headings you want to animate and loop through them, applying the same animation options to each element.

const headings = document.querySelectorAll("h2"); headings.forEach((heading) => { textAnimator.animateOnScroll(heading); }); 

In this example, SplitFX applies the scroll-triggered animation to each selected heading individually. Each heading triggers its animation when it enters the viewport.

Complete Example

Imagine a webpage with multiple sections, each having its own heading. You want each heading to animate when it enters the viewport as visitors scroll through the page. You can achieve this with SplitFX:

<!-- Load the SplitFX plugin from jsDelivr --> <script src="https://cdn.jsdelivr.net/npm/@tanglat/splitfx@1/dist/umd/splitfx.min.js"></script> 
// Select all section headings you want to animate const headings = document.querySelectorAll(".section-heading"); // Create a SplitFX instance and define how the text should be animated. const textAnimator = new SplitFX({ "in": { "animation": "fadeRight", "duration": 1000, "stagger": 40 }, "out": { "mode": "words", "duration": 0, "stagger": 0 } } ); // Apply the scroll animation to each heading headings.forEach((heading) => { textAnimator.animateOnScroll(heading, { repeat: false, observerOptions: { threshold: 1 // Trigger when the heading is fully visible } }); }); 

With this approach, you can apply the same scroll animation to multiple section headings without configuring each one separately. SplitFX handles each heading individually, triggering its animation when it becomes fully visible in the viewport. You can customize the animation and observer options to achieve the effect you want.