profile picture of Olivier Larose

Olivier Larose

February 23, 2024

/

Beginner

/

Short

Text Along Path

How to Move a Text along an SVG Path on Scroll using React and Framer Motion

a website tutorial on how to animate a a Text along an SVG Path on Scroll using React and Framer Motion. Used with the Lenis Scroll for added smoothness and Next.js

Live DemoSource code
background video

Initializing the project

Let's start the project by creating a Next.js application. We can do that by running npx create-next-app@latest client inside of a terminal.

Adding the HTML and CSS

We can delete everything in the page.js , global.css and page.module.css and add our own HTML and CSS, to start with a nice blank application.

  • We will use Framer Motion for the animation, so we can run npm i framer-motion.
  • We will use the Lenis Scroll for the smooth scrolling, so we can run npm i @studio-freight/lenis.

page.js

1

import Footer from "@/components/Footer";

2

3

export default function Home() {

4

return (

5

<main>

6

<div className="h-[100vh]"></div>

7

<Footer />

8

</main>

9

);

10

}

Adding a Sticky Footer

To enhance the effect of the animation, we can start by creating a sticky footer, which will add extra space at the bottom of the window, giving more scrolling time for the path to be moved along a path.

The first step to do that is to get the progress of the scroll. We can do that by using the useScroll hook:

useScroll hook

1

import { useScroll } from 'framer-motion';

2

3

const container = useRef();

4

const { scrollYProgress } = useScroll({

5

target: container,

6

offset: ['start end', 'end end']

7

})
  • scrollYProgress returns a value between 0 and 1 that represents the progress of the scroll based on the target and the offset.
  • offset: The tracker starts at ['start end'] the start of the target and the end of the window and ends at ['end end'] the end of the target and the end of the window.

The parallax effect is used by mixing the scrollYProgress and the useTransform hook.

useTransform hook

1

const y = useTransform(scrollProgress, [0, 1], [-200, 0])
  • When the scrollYProgress is between 0 and 1 then the y value will be between -200 and 0.

Mixing everything together:

Footer.jsx

1

'use client';

2

import React, { useRef } from "react";

3

import { useScroll, useTransform, motion } from 'framer-motion';

4

5

export default function Footer() {

6

const container = useRef();

7

const { scrollYProgress } = useScroll({

8

target: container,

9

offset: ['start end', 'end end']

10

})

11

12

return (

13

<div ref={container}>

14

<Logos scrollProgress={scrollYProgress}/>

15

</div>

16

)

17

}

18

19

const Logos = ({scrollProgress}) => {

20

const y = useTransform(scrollProgress, [0, 1], [-225, 0])

21

return (

22

<div className="h-[250px] bg-black overflow-hidden">

23

<motion.div style={{y}} className="h-full bg-black flex justify-center gap-10 items-center p-10">

24

{

25

[...Array(5)].map((_, i) => {

26

return <img key={`img_${i}`} className="w-[80px] h-[80px]" src={`/medias/${i+1}.jpg`} />

27

})

28

}

29

</motion.div>

30

</div>

31

)

32

}

We should have something like this:

Adding an SVG Path

  • The SVG can be made in any Vector based tool like Illustrator or Figma.

Footer.jsx

1

return (

2

<div ref={container}>

3

<svg className="w-full mb-40" viewBox="0 0 250 90">

4

<path fill="none" stroke="black" d="m0,88.5c61.37,0,61.5-68,126.5-68,58,0,51,68,123,68"/>

5

</svg>

6

<Logos scrollProgress={scrollYProgress}/>

7

</div>

8

)
Screenshot of the path

Adding Text Along it

Text Path

1

return (

2

<div ref={container}>

3

<svg className="w-full mb-40" viewBox="0 0 250 90">

4

<path fill="none" id="curve" d="m0,88.5c61.37,0,61.5-68,126.5-68,58,0,51,68,123,68"/>

5

<text className="text-[6px] uppercase" style={{fill: "red"}}>

6

{

7

[...Array(3)].map((_, i) => {

8

return <textPath key={i} startOffset={i * 40 + "%"} href="#curve">Curabitur mattis efficitur velit</textPath>

9

})

10

}

11

</text>

12

</svg>

13

<Logos scrollProgress={scrollYProgress}/>

14

</div>

15

)
  • To stick the textPath to the path, all you have to do is add an href and an id to them.

We should have something like this:

Screenshot of the path

Moving the Text on Scroll

Next up we're going to move the text along the path on scroll. To do that all we have to do is use the previously created scrollYProgress.

We also have to add refs to each textPath, in order to target them and change their styling.

Adding Refs

1

<text className="text-[6px] uppercase" style={{fill: "red"}}>

2

{

3

[...Array(3)].map((_, i) => {

4

return <textPath key={i} ref={ref => paths.current[i] = ref} startOffset={i * 40 + "%"} href="#curve">Curabitur mattis efficitur velit</textPath>

5

})

6

}

7

</text>

Animating on scroll

To animate on scroll, there are multiple ways of doing it, but for now, we can simply listen to the scroll event and adjust the offset.

Animating on scroll

1

useEffect( () => {

2

scrollYProgress.on("change", e => {

3

paths.current.forEach( (path, i) => {

4

path.setAttribute("startOffset", -40 + (i * 40) + (e * 40) + "%");

5

})

6

})

7

}, [])

Finally we can add a smooth scroll to make everything a bit cleaner.

page.js

1

useEffect( () => {

2

const lenis = new Lenis()

3

4

function raf(time) {

5

lenis.raf(time)

6

requestAnimationFrame(raf)

7

}

8

9

requestAnimationFrame(raf)

10

}, [])

We should have something like this:

Wrapping up

That's it for this tutorial!

It's actually super easy to move a text along a path and the result is super nice too! Hope you learned something!

-Oli

Related Animations

image

June 2, 2024

Mask Section Transition

A website tutorial featuring a scroll animation using an SVG Mask to create a section transition, made with React, Framer Motion. Inspired by: https://axelvanhessche.com/. Pictures by Eric Asamoah, Inka and Niclas Lindergård, Daniel Ribar

image

May 25, 2024

Background Image Parallax

A website animation featuring a background image moving on scroll in a parallax motion, made with Framer Motion and React, inside a Next.js app. Inspired by: https://inkfishnyc.com/. Pictures by Matthias Leidinger

image

May 25, 2024

Text Parallax

A website animation featuring a Text Parallax with sliding text on scroll, made with Framer Motion and React, inside a Next.js app