Text Gradient Scroll
The text gradient scroll component is designed to enhance user interaction by providing a visually dynamic effect as the user scrolls through the text. Unlike static text, this effect offers a more engaging visual experience with smooth color transitions that change as the text is scrolled. The animated gradient shifts add a modern and interactive touch to the user experience. This example was created using Tailwind CSS and Framer Motion.
Install the following dependencies:
npm i framer-motion clsx tailwind-merge
Add util file
import { ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Copy and paste the following code into your project.
"use client";
import React, { createContext, useContext, useRef } from "react";
import { useScroll, useTransform, motion, MotionValue } from "framer-motion";
import { cn } from "@/lib/utils";
type TextOpacityEnum = "none" | "soft" | "medium";
type ViewTypeEnum = "word" | "letter";
type TextGradientScrollType = {
text: string;
type?: ViewTypeEnum;
className?: string;
textOpacity?: TextOpacityEnum;
};
type LetterType = {
children: React.ReactNode | string;
progress: MotionValue<number>;
range: number[];
};
type WordType = {
children: React.ReactNode;
progress: MotionValue<number>;
range: number[];
};
type CharType = {
children: React.ReactNode;
progress: MotionValue<number>;
range: number[];
};
type TextGradientScrollContextType = {
textOpacity?: TextOpacityEnum;
type?: ViewTypeEnum;
};
const TextGradientScrollContext = createContext<TextGradientScrollContextType>(
{}
);
function useGradientScroll() {
const context = useContext(TextGradientScrollContext);
return context;
}
export default function TextGradientScroll({
text,
className,
type = "letter",
textOpacity = "soft",
}: TextGradientScrollType) {
const ref = useRef<HTMLParagraphElement>(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start center", "end center"],
});
const words = text.split(" ");
return (
<TextGradientScrollContext.Provider value={{ textOpacity, type }}>
<p ref={ref} className={cn("relative flex m-0 flex-wrap", className)}>
{words.map((word, i) => {
const start = i / words.length;
const end = start + 1 / words.length;
return type === "word" ? (
<Word key={i} progress={scrollYProgress} range={[start, end]}>
{word}
</Word>
) : (
<Letter key={i} progress={scrollYProgress} range={[start, end]}>
{word}
</Letter>
);
})}
</p>
</TextGradientScrollContext.Provider>
);
}
const Word = ({ children, progress, range }: WordType) => {
const opacity = useTransform(progress, range, [0, 1]);
return (
<span className="relative me-2 mt-2">
<span style={{ position: "absolute", opacity: 0.1 }}>{children}</span>
<motion.span style={{ transition: "all .5s", opacity: opacity }}>
{children}
</motion.span>
</span>
);
};
const Letter = ({ children, progress, range }: LetterType) => {
if (typeof children === "string") {
const amount = range[1] - range[0];
const step = amount / children.length;
return (
<span className="relative me-2 mt-2">
{children.split("").map((char: string, i: number) => {
const start = range[0] + i * step;
const end = range[0] + (i + 1) * step;
return (
<Char key={`c_${i}`} progress={progress} range={[start, end]}>
{char}
</Char>
);
})}
</span>
);
}
};
const Char = ({ children, progress, range }: CharType) => {
const opacity = useTransform(progress, range, [0, 1]);
const { textOpacity } = useGradientScroll();
return (
<span>
<span
className={cn("absolute", {
"opacity-0": textOpacity == "none",
"opacity-10": textOpacity == "soft",
"opacity-30": textOpacity == "medium",
})}
>
{children}
</span>
<motion.span
style={{
transition: "all .5s",
opacity: opacity,
}}
>
{children}
</motion.span>
</span>
);
};
Usage
import TextGradientScroll from "@/components/ui/text-gradient-scroll";
export default function TextGradientScrollExample() {
return (
<TextGradientScroll text="The text gradient scroll component is designed to enhance user interaction by providing a visually dynamic effect as the user scrolls through the text. Unlike static text, this effect offers a more engaging visual experience with smooth color transitions that change as the text is scrolled. The animated gradient shifts add a modern and interactive touch to the user experience. This example was created using Tailwind CSS and Framer Motion." />
);
}
API
Prop | Type | Default | Description |
---|---|---|---|
text | string | The text content to display with gradient effect. | |
className | string | Optional CSS class for styling the component. | |
type | "letter" | "word" | "letter" | Determines the type of animation, whether it applies to letters or words. |
textOpacity | "none" | "soft" | "medium" | "soft" | Sets the opacity level for the text: none, soft, medium, or strong. |