Text Highlight on Scroll

Words progressively fill with color as you scroll through the text

animationtextscrollhighlightreading
Install dependencies
$npm install framer-motion
Preview

Source Code

"use client";

import { useRef } from "react";
import { motion, useScroll, useTransform } from "framer-motion";

interface TextHighlightScrollProps {
  text: string;
  highlightColor?: string;
  baseColor?: string;
  className?: string;
}

function Word({
  word,
  progress,
  start,
  end,
  highlightColor,
  baseColor,
}: {
  word: string;
  progress: import("framer-motion").MotionValue<number>;
  start: number;
  end: number;
  highlightColor: string;
  baseColor: string;
}) {
  const color = useTransform(progress, [start, end], [baseColor, highlightColor]);

  return (
    <motion.span style={{ color }} className="inline-block transition-colors">
      {word}&nbsp;
    </motion.span>
  );
}

export default function TextHighlightScroll({
  text,
  highlightColor = "#fff",
  baseColor = "rgba(255,255,255,0.2)",
  className = "",
}: TextHighlightScrollProps) {
  const containerRef = useRef<HTMLDivElement>(null);

  const { scrollYProgress } = useScroll({
    target: containerRef,
    offset: ["start 0.8", "end 0.3"],
  });

  const words = text.split(" ");
  const totalWords = words.length;

  return (
    <div ref={containerRef} className={`${className}`}>
      <p className="flex flex-wrap text-2xl font-medium leading-relaxed md:text-3xl lg:text-4xl">
        {words.map((word, i) => {
          const start = i / totalWords;
          const end = (i + 1) / totalWords;
          return (
            <Word
              key={i}
              word={word}
              progress={scrollYProgress}
              start={start}
              end={end}
              highlightColor={highlightColor}
              baseColor={baseColor}
            />
          );
        })}
      </p>
    </div>
  );
}