Text Along Path
A text component that animates along an SVG path.
Installation
npx shadcn@latest add "https://fancycomponents.dev/r/text-along-path.json"
Usage
There are two types of animations available for this component, which you can control with the animationType
prop:
auto
— plays the animation automatically when the text is initially rendered. This is the default setting.scroll
— drives the animation with the scroll position of the container. To use this component, you'll need to provide an SVG path via thepath
prop. You can create this path using:
- Design tools like Figma, Illustrator, or any online SVG editor
- Code, by constructing the path programmatically
The component only requires the d
attribute from your SVG path and the viewBox
attribute from the SVG container.
Path ID
Each path needs a unique id
to properly reference it in the text elements. While the component includes a basic ID generator, it's recommended to provide your own via the pathId
prop, especially when using multiple instances of the component. This ensures animations remain distinct and don't interfere with each other.
Sizing and ViewBox
The SVG container can be sized flexibly - by default it will expand to fill its parent container. The viewBox
attribute can be any dimensions, but it's recommended to:
- Match the aspect ratio you want the final component to have
- Use dimensions that make sense for your path coordinates
For example, if your path coordinates span 0-500 on x and 0-100 on y, a viewBox of "0 0 500 100" would be appropriate.
Understanding the component
The component consist an svg container with a path element, and two text elements with textPath
elements inside. The textPath
elements are used to animate the text along the path. When it is used with the auto
animation type, we use an animate
element to animate the text along the path. When it is used with the scroll
animation type, we animate the startOffset
attribute of the textPath
elements to scroll the text along the path.
Auto animation
The auto
animation type is the default setting, and it plays the animation automatically when the text is initially rendered. We start at 0% offset and animate to 100% offset, which means the text will start at the beginning of the path and end at the end of the path.
The relevant props for the auto
animation type are:
duration
— the duration of the animation in millisecondsrepeatCount
— the number of times the animation should repeat. You can also set this toindefinite
to make the animation repeat indefinitely (default setting)
Animation on closed paths
You might notice the component uses two identical text elements with textPath
elements when you use the auto
animation type. The reason for this to achieve the illusion of continuous movement on a closed path. Here is how it works:
- The first text element starts at the beginning of the path and animates forward
- The second text element follows behind the first one at an offset
- When the first text reaches the end of the path, the second text has moved into position to continue the animation
- This creates the illusion of continuous movement without any visible jumps or gaps
This dual-text approach is necessary because animating a single text element would result in a noticeable "jump" when the animation resets back to the start position.
See an example of this in the first, and the following demo above:
This example above also demonstrates how to use the easingFunction
prop to create more interesting animations. Please refer to the (mdn docs)[https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function] on what values you can use.
Another important note here is that you have to experiment with the text length and size, to ensure the text doesn't overlap with each other, since it's not calculated automatically.
Preserve aspect ratio
The preserveAspectRatio
attribute controls how the SVG content scales to fit its container when their aspect ratios differ. This is determined by comparing the viewBox
dimensions to the actual SVG container size. For example, with preserveAspectRatio="xMidYMid meet"
, the path and text will be centered both horizontally and vertically while maintaining proportions.
Please refer to the MDN docs for the poossible values. In short, the default value xMidYMid meet
will work for most cases. If you set it to none
, the SVG container will be stretched to the container size, but will also result in a distortion of the text. Check out this behaviour on the first demo. Resize your viewport to see the difference.
Scroll
By setting the animationType
prop to scroll
, you can control the animation with the scroll position of the container. For tracking the scroll position, we use the useScroll
hook from motion/react
.
The relevant props are:
scrollContainer
— a ref to the container element that the scroll animation will be driven byscrollOffset
— the scroll offset range for the animationscrollTransformValues
— ThescrollYProgress
value returned byuseScroll
hook ranges between 0 and 1, and this prop defines how we should map these values to thestartOffset
attribute of the text elements. It will be converted to percentage values.
Please refer to the motion docs for more details.
SCROLL DOWN
Notes
The performance impact of the animation increases with the length and complexity of the path, especially if you're using multiple instances, so keep an eye on it :).
Props
Prop | Type | Default | Description |
---|---|---|---|
path* | string | - | The path to be animated |
text* | string | - | The text to be animated |
pathId | string | - | The ID for the path |
pathClassName | string | - | Additional CSS classes for the path |
preserveAspectRatio | PerserveAspectRatio | "xMidYMid meet" | The aspect ratio to preserve when scaling the SVG |
showPath | boolean | false | Whether to show the path |
width | string | number | 100% | The width of the SVG container |
height | string | number | 100% | The height of the SVG container |
viewBox | string | "0 0 100 100" | The viewBox of the SVG container |
svgClassName | string | - | Additional CSS classes for the SVG container |
textClassName | string | - | Additional CSS classes for the text |
textAnchor | "start" | "middle" | "end" | "start" | The text anchor of the text |
animationType | "auto" | "scroll" | "auto" | The animation type |
duration | number | 4 | The duration of the animation in milliseconds |
repeatCount | number | "indefinite" | "indefinite" | The number of times the animation should repeat |
easingFunction | { calcMode?: string; keyTimes?: string; keySplines?: string } | - | The easing function for the animation |
scrollContainer | RefObject<HTMLElement> | - | The ref to the container element that the scroll animation will be driven by |
scrollOffset | UseScrollOptions["offset"] | ["start end", "end end"] | The scroll offset range for the animation |
scrollTransformValues | [number, number] | [0, 100] | The scrollYProgress value returned by useScroll hook ranges between 0 and 1, and this prop defines how we should map these values to the startOffset attribute of the text elements. It will be converted to percentage values. |