JSFiddle - React, Tailwind, and code Playground

by Jordan Sayner

HTML

<svg xmlns="http://www.w3.org/2000/svg" width="333" height="288" viewBox="0 0 333 288" fill="none" data-stroke="80">
  <path d="M275.337 275.149C335.323 215.164 335.323 117.909 275.337 57.9236C215.352 -2.0616 118.097 -2.0616 58.1118 57.9236C-1.87339 117.909 -1.87339 215.164 58.1118 275.149" stroke="#E9E9E4" stroke-width="24.5763" stroke-linecap="round"/>
  <path d="M275.337 275.149C335.323 215.164 335.323 117.909 275.337 57.9236C215.352 -2.0616 118.097 -2.0616 58.1118 57.9236C-1.87339 117.909 -1.87339 215.164 58.1118 275.149" stroke="red" stroke-width="24.5763" stroke-linecap="round" style="stroke-dasharray: 723.932; stroke-dashoffset: 723.932;"/>
</svg>

<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />

<svg xmlns="http://www.w3.org/2000/svg" width="333" height="288" viewBox="0 0 333 288" fill="none" data-stroke="70">
  <path d="M275.337 275.149C335.323 215.164 335.323 117.909 275.337 57.9236C215.352 -2.0616 118.097 -2.0616 58.1118 57.9236C-1.87339 117.909 -1.87339 215.164 58.1118 275.149" stroke="#E9E9E4" stroke-width="24.5763" stroke-linecap="round"/>
  <path d="M275.337 275.149C335.323 215.164 335.323 117.909 275.337 57.9236C215.352 -2.0616 118.097 -2.0616 58.1118 57.9236C-1.87339 117.909 -1.87339 215.164 58.1118 275.149" stroke="red" stroke-width="24.5763" stroke-linecap="round" style="stroke-dasharray: 723.932; stroke-dashoffset: 723.932;"/>
</svg>

<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />

<svg xmlns="http://www.w3.org/2000/svg" width="333" height="288" viewBox="0 0 333 288" fill="none" data-stroke="12">
  <path d="M275.337 275.149C335.323...

CSS

svg {
  transform: scaleX(-1);
}

JavaScript

function animatePath(path, strokePercent) {
  const length = path.getTotalLength();
  const strokeLength = (strokePercent / 100) * length; // Calculate the desired stroke length

  path.style.strokeDasharray = length;
  path.style.strokeDashoffset = length; // Start fully hidden (off-path)

  // Animate stroke from fully hidden (length) to 0 (fully visible from left to right)
  path.animate(
    [{ strokeDashoffset: length }, { strokeDashoffset: length - strokeLength }],
    { duration: 2000, easing: "ease-out", fill: "forwards" }
  );
}

const observer = new IntersectionObserver(
  (entries, observer) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const svg = entry.target;
        const path = svg.querySelector("path:nth-of-type(2)"); // Select the animated path
        const strokePercent = parseFloat(svg.getAttribute("data-stroke")) || 100;

        animatePath(path, strokePercent);
        observer.unobserve(svg); // Stop observing once the animation is triggered
      }
    });
  },
  { threshold: 0.2 } // Trigger when 20% of SVG is in view
);

document.querySelectorAll("svg").forEach((svg) => observer.observe(svg));