More
Click

Easy-Peasy GSAP Link Animations in React

Category:  nerd
Date:  
Author:  Ryan McManimie

Back in the halcyon days, before TikTok, NFTs, and Conde Nast gutting Wired Magazine like a Thanksgiving turkey, their website utilized this blue highlighter underline effect for hyperlinks that I always found attractive.

What if we took that but applied a modern makeover by making it seem as if some invisible, digital elf was highlighting them in real-time as we scrolled down the page?

Like this! (I'm sure you already saw it but let's just pretend it was a well-timed reveal)

Anyway, the implementation is pretty trivial.

First some CSS. The effect here is just a background image, shaped using linear-gradient to mimic the look of a underline, and then animating it across using CSS transitions when the active class is added to it.

:root {
  --color-text-highlight: #333;
  --bg-color-highlight: #87d49a;
  --bg-color-highlight-hover: #a1e3b2;
  --line-size: 0.25em;
  --ease: cubic-bezier(0.30, 1, 0.5, 1);
  --duration: 1.5s;
}

.digital-elf-link {
  background-repeat: no-repeat;
  background-size: 0% 100%;
  cursor: pointer;
  font-weight: 300;
  color: #000;

  background-image: linear-gradient(
    transparent calc(100% - var(--line-size)),
    var(--bg-color-highlight) var(--line-size)
  );

  transition:
    background-color calc(var(--duration) / 4) var(--ease),
    background-size var(--duration) var(--ease);

  &.active {
    background-size: 100% 100%;
  }

  &:hover {
    background-image: linear-gradient(
      transparent calc(100% - var(--line-size)),
      var(--bg-color-highlight-hover) var(--line-size)
    );
  }
}

And for that, we'll use GSAP. Let's create a custom hook and toss our GSAP code in there. ScrollTrigger has a light lift here, only being leveraged to 'activate' the links as they appear so CSS can work its magic.

// useLinkHighligher.js

import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { useGSAP } from '@gsap/react';

gsap.registerPlugin(ScrollTrigger);

const useLinkHighlighter = () => {
  useGSAP(() => {
    const highlights = gsap.utils.toArray("p .digital-elf-link");

    highlights.forEach((highlight) => {
      ScrollTrigger.create({
        start: "-120px center",
        trigger: highlight,    
        onEnter: () => highlight.classList.add("active")
      });
    });
  }, []);
};

export default useLinkHighlighter;

From there, just import, call, and Bob's your uncle. Happy highlighting.

import useLinkHighlighter from "@/src/lib/useLinkHighlighter";
// ...
useLinkHighlighter();