import React from "react";
import styles from "./GradientText.module.css";
type GradientTextProps<T extends React.ElementType = "span"> = {
as?: T;
children: React.ReactNode;
gradient?: string;
animated?: boolean;
speed?: string;
className?: string;
style?: React.CSSProperties;
} & Omit<
React.ComponentPropsWithoutRef<T>,
"as" | "children" | "className" | "style"
>;
function cn(...classes: Array<string | false | null | undefined>) {
return classes.filter(Boolean).join(" ");
}
function GradientText<T extends React.ElementType = "span">({
as,
children,
gradient = "linear-gradient(90deg, #7E22CE 0%, #EC4899 50%, #22D3EE 100%)",
animated = false,
speed = "4s",
className,
style,
...props
}: GradientTextProps<T>) {
const Component = as || "span";
return (
<Component
className={cn(
styles.gradientText,
animated && styles.animated,
className,
)}
style={
{
"--gradient-text-bg": gradient,
"--gradient-text-speed": speed,
...style,
} as React.CSSProperties
}
{...props}
>
{children}
</Component>
);
}
export default GradientText;Component details
Overview, install command, dependencies, and project links.
A reusable gradient text component built with React, TypeScript, and CSS Modules. Accepts any gradient string via the gradient prop so you can pass any linear-gradient, radial-gradient, or conic-gradient you want. The animated prop enables a smooth infinite scrolling gradient animation driven by a CSS background-position keyframe - speed is controlled via the speed prop so you can pass "2s" for fast or "8s" for slow without touching any CSS. The as prop is fully polymorphic - render the gradient text as h1, h2, p, span, or any valid HTML element with full TypeScript type safety. Respects prefers-reduced-motion - animation automatically stops for users who have reduced motion enabled in their OS settings. Uses CSS custom properties to pass gradient and speed values from React props into the stylesheet, keeping all animation logic in CSS where it belongs.
Discussion
Feedback, implementation tips, and usage notes.
Comments
Sign in to join the conversation
