Web InnoventixFreeCode

Gradient Animate Text Effect

Original · free

animated gradient text

byWeb InnoventixReact + Tailwind
txfxgradientanimatetext-effects
Open

Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.

npx shadcn@latest add https://webinnoventix.com/r/txfx-gradient-animate.json
txfx-gradient-animate.tsx
"use client";

import { motion, useReducedMotion, type Variants } from "motion/react";

type GradientSample = {
  id: string;
  index: string;
  name: string;
  heading: string;
  meta: string;
  gradient: string;
  duration: string;
};

const SAMPLES: readonly GradientSample[] = [
  {
    id: "aurora",
    index: "01",
    name: "Aurora",
    heading: "Type that refuses to sit still.",
    meta: "clip · 7s · indigo → violet → sky",
    gradient:
      "linear-gradient(100deg, #4f46e5, #7c3aed, #0ea5e9, #7c3aed, #4f46e5)",
    duration: "7s",
  },
  {
    id: "verdant",
    index: "02",
    name: "Verdant",
    heading: "Color that flows through every letter.",
    meta: "clip · 9s · emerald → sky → indigo",
    gradient:
      "linear-gradient(100deg, #059669, #0284c7, #4338ca, #0284c7, #059669)",
    duration: "9s",
  },
  {
    id: "ember",
    index: "03",
    name: "Ember",
    heading: "One CSS trick, endless motion.",
    meta: "clip · 11s · rose → amber → violet",
    gradient:
      "linear-gradient(100deg, #e11d48, #d97706, #7c3aed, #d97706, #e11d48)",
    duration: "11s",
  },
];

const TXFX_STYLES = `
.txfx-ga-clip {
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  background-size: 200% auto;
  background-position: 0% 50%;
  animation-name: txfx-ga-flow;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  will-change: background-position;
}
.txfx-ga-bar {
  background-size: 200% auto;
  background-position: 0% 50%;
  animation-name: txfx-ga-flow;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes txfx-ga-flow {
  0% { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .txfx-ga-clip,
  .txfx-ga-bar {
    animation: none !important;
    background-position: 0% 50%;
  }
}
`;

const GRID_MASK = "radial-gradient(ellipse at center, black 55%, transparent 100%)";

export default function TxfxGradientAnimate() {
  const reduce = useReducedMotion();

  const container: Variants = {
    hidden: {},
    visible: {
      transition: { staggerChildren: reduce ? 0 : 0.12, delayChildren: 0.04 },
    },
  };

  const item: Variants = {
    hidden: { opacity: reduce ? 1 : 0, y: reduce ? 0 : 26 },
    visible: {
      opacity: 1,
      y: 0,
      transition: { duration: reduce ? 0 : 0.65, ease: "easeOut" },
    },
  };

  return (
    <section className="relative w-full overflow-hidden bg-neutral-50 px-6 py-24 dark:bg-neutral-950 sm:py-32">
      <style>{TXFX_STYLES}</style>

      {/* atmosphere */}
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-0"
        style={{
          backgroundImage:
            "linear-gradient(to right, rgba(120,120,135,0.07) 1px, transparent 1px), linear-gradient(to bottom, rgba(120,120,135,0.07) 1px, transparent 1px)",
          backgroundSize: "56px 56px",
          maskImage: GRID_MASK,
          WebkitMaskImage: GRID_MASK,
        }}
      />
      <div
        aria-hidden="true"
        className="pointer-events-none absolute -top-24 left-1/4 h-72 w-72 rounded-full bg-violet-500/20 blur-3xl dark:bg-violet-600/20"
      />
      <div
        aria-hidden="true"
        className="pointer-events-none absolute -bottom-16 right-1/4 h-72 w-72 rounded-full bg-sky-400/20 blur-3xl dark:bg-sky-500/20"
      />

      <motion.div
        variants={container}
        initial="hidden"
        whileInView="visible"
        viewport={{ once: true, margin: "-80px" }}
        className="relative mx-auto max-w-5xl"
      >
        {/* eyebrow */}
        <motion.div variants={item}>
          <span className="inline-flex items-center gap-2 rounded-full border border-neutral-200 bg-white/60 px-3 py-1 text-xs font-medium tracking-wide text-neutral-600 backdrop-blur dark:border-neutral-800 dark:bg-neutral-900/60 dark:text-neutral-300">
            <svg
              viewBox="0 0 24 24"
              width="13"
              height="13"
              fill="none"
              stroke="currentColor"
              strokeWidth="1.8"
              strokeLinecap="round"
              strokeLinejoin="round"
              aria-hidden="true"
            >
              <path d="M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9L12 3z" />
            </svg>
            FreeCode · Text Effects
          </span>
        </motion.div>

        {/* intro */}
        <motion.h2
          variants={item}
          className="mt-6 max-w-2xl text-balance text-3xl font-semibold tracking-tight text-neutral-900 dark:text-neutral-50 sm:text-4xl"
        >
          Headlines with a gradient that never stops flowing.
        </motion.h2>
        <motion.p
          variants={item}
          className="mt-4 max-w-xl text-base leading-relaxed text-neutral-600 dark:text-neutral-400"
        >
          A single keyframed{" "}
          <code className="rounded bg-neutral-100 px-1.5 py-0.5 font-mono text-[0.85em] text-neutral-800 dark:bg-neutral-800 dark:text-neutral-200">
            background-position
          </code>{" "}
          shift, clipped straight to the letters. Three palettes, one technique —
          legible in light and dark, and it settles the moment a visitor prefers
          reduced motion.
        </motion.p>

        {/* samples */}
        <div className="mt-14 space-y-12 sm:mt-16 sm:space-y-16">
          {SAMPLES.map((sample) => (
            <motion.div key={sample.id} variants={item}>
              <div className="flex items-center gap-3">
                <span className="font-mono text-xs font-medium text-neutral-400 dark:text-neutral-500">
                  {sample.index}
                </span>
                <span className="h-px w-6 bg-neutral-300 dark:bg-neutral-700" />
                <span className="font-mono text-xs uppercase tracking-[0.18em] text-neutral-500 dark:text-neutral-400">
                  {sample.name}
                </span>
              </div>

              <h3
                className="txfx-ga-clip mt-3 max-w-3xl text-balance text-5xl font-black leading-[1.04] tracking-tight sm:text-6xl md:text-7xl"
                style={{
                  backgroundImage: sample.gradient,
                  animationDuration: sample.duration,
                }}
              >
                {sample.heading}
              </h3>

              <div className="mt-5 flex items-center gap-3">
                <span
                  className="txfx-ga-bar h-1 w-16 rounded-full"
                  style={{
                    backgroundImage: sample.gradient,
                    animationDuration: sample.duration,
                  }}
                  aria-hidden="true"
                />
                <span className="font-mono text-xs text-neutral-500 dark:text-neutral-500">
                  {sample.meta}
                </span>
              </div>
            </motion.div>
          ))}
        </div>

        {/* footer note */}
        <motion.div
          variants={item}
          className="mt-16 flex flex-wrap items-center gap-x-2 gap-y-1 border-t border-neutral-200 pt-6 text-sm text-neutral-500 dark:border-neutral-800 dark:text-neutral-400"
        >
          <span className="font-medium text-neutral-700 dark:text-neutral-300">
            Built with
          </span>
          <code className="rounded bg-neutral-100 px-1.5 py-0.5 font-mono text-[0.82em] text-neutral-800 dark:bg-neutral-800 dark:text-neutral-200">
            background-clip: text
          </code>
          <span>and a looping</span>
          <code className="rounded bg-neutral-100 px-1.5 py-0.5 font-mono text-[0.82em] text-neutral-800 dark:bg-neutral-800 dark:text-neutral-200">
            @keyframes
          </code>
          <span>— no canvas, no images, no runtime cost.</span>
        </motion.div>
      </motion.div>
    </section>
  );
}

Dependencies

motion

Licence

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

Similar components

Browse all →