Pure TailwindMIT licensed

Tailwind Animated Gradient Text (Moving Gradient)

A hero where colour flows through one word on a perfectly seamless loop. The gradient is a repeating tile twice the element's width, and animate-ttg08-flow moves it exactly one tile per cycle — fixing the visible jump the CSS original had at the end of every loop. Hover to pause.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="ttg-08 relative isolate w-full min-h-svh grid place-items-center overflow-hidden bg-ttg08-bg px-6 py-20 font-ttg08-sans text-ttg08-ink" aria-labelledby="ttg08-title">
  <span aria-hidden="true" class="absolute inset-x-0 top-0 -z-10 h-2/3 bg-[radial-gradient(50%_60%_at_50%_0%,var(--color-ttg08-glow),transparent)]"></span>
  <div class="max-w-3xl text-center">
    <p class="inline-flex items-center gap-2 rounded-full border border-white/10 px-3.5 py-1.5 text-xs font-medium tracking-[0.08em] text-ttg08-mut uppercase"><span aria-hidden="true" class="size-1.5 rounded-full bg-ttg08-c3"></span>Season 3 — now streaming</p>
    <h1 id="ttg08-title" class="mt-7 font-ttg08-display text-[clamp(2.75rem,9vw,6rem)] leading-[1] font-extrabold tracking-[-0.045em]">The future of<br><span class="bg-[linear-gradient(90deg,var(--color-ttg08-c1),var(--color-ttg08-c2),var(--color-ttg08-c3),var(--color-ttg08-c4),var(--color-ttg08-c1))] bg-[length:200%_100%] bg-clip-text pr-[0.04em] text-transparent animate-ttg08-flow hover:[animation-play-state:paused] motion-reduce:animate-none">interface</span> design</h1>
    <p class="mx-auto mt-7 max-w-lg text-[17px]/[1.7] text-ttg08-mut text-pretty">Shifting gradients bring motion and energy to a headline without a single line of JavaScript. Hover the word to freeze it.</p>
    <p aria-hidden="true" class="mt-10 font-mono text-[11.5px] text-ttg08-mut/80">bg-[length:200%_100%] · animate-ttg08-flow · hover:[animation-play-state:paused]</p>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-ttg08-bg: #08080f;
  --color-ttg08-bg: oklch(0.14 0.015 285);
  --color-ttg08-glow: #3b2a6e80;
  --color-ttg08-glow: oklch(0.35 0.11 290 / 0.5);
  --color-ttg08-ink: #f6f7fb;
  --color-ttg08-ink: oklch(0.975 0.005 270);
  --color-ttg08-mut: #a7adbb;
  --color-ttg08-mut: oklch(0.76 0.018 270);
  --color-ttg08-c1: #f39cf5;
  --color-ttg08-c1: oklch(0.8 0.16 325);
  --color-ttg08-c2: #8a8ff9;
  --color-ttg08-c2: oklch(0.69 0.16 280);
  --color-ttg08-c3: #3cc4f5;
  --color-ttg08-c3: oklch(0.77 0.14 225);
  --color-ttg08-c4: #3fdca2;
  --color-ttg08-c4: oklch(0.81 0.15 165);
  --font-ttg08-display: 'Syne', system-ui, sans-serif;
  --font-ttg08-sans: 'Geist', system-ui, sans-serif;
  --animate-ttg08-flow: ttg08-flow 6s linear infinite;

  @keyframes ttg08-flow {
    from {
      background-position: 0% 50%;
    }

    to {
      background-position: 200% 50%;
    }
  }
}

.ttg-08 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-ttg08-bg: #08080f;
  --color-ttg08-bg: oklch(0.14 0.015 285);
  --color-ttg08-glow: #3b2a6e80;
  --color-ttg08-glow: oklch(0.35 0.11 290 / 0.5);
  --color-ttg08-ink: #f6f7fb;
  --color-ttg08-ink: oklch(0.975 0.005 270);
  --color-ttg08-mut: #a7adbb;
  --color-ttg08-mut: oklch(0.76 0.018 270);
  --color-ttg08-c1: #f39cf5;
  --color-ttg08-c1: oklch(0.8 0.16 325);
  --color-ttg08-c2: #8a8ff9;
  --color-ttg08-c2: oklch(0.69 0.16 280);
  --color-ttg08-c3: #3cc4f5;
  --color-ttg08-c3: oklch(0.77 0.14 225);
  --color-ttg08-c4: #3fdca2;
  --color-ttg08-c4: oklch(0.81 0.15 165);
  --font-ttg08-display: 'Syne', system-ui, sans-serif;
  --font-ttg08-sans: 'Geist', system-ui, sans-serif;
  --animate-ttg08-flow: ttg08-flow 6s linear infinite;

  @keyframes ttg08-flow {
    from {
      background-position: 0% 50%;
    }

    to {
      background-position: 200% 50%;
    }
  }
}

.ttg-08 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Syne:wght@600..800&family=Geist:wght@400..600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • @keyframes tg-08-shift + the animation: declaration became one --animate-ttg08-flow token; the class animate-ttg08-flow is all the markup needs.
  • Bug fix: the original's 300%/0→100% loop jumped every cycle; 200%/0→200% on a repeating tile is mathematically seamless.
  • UI upgrade: hover pauses the flow, Syne gives the display line a distinctive voice, and a soft top glow plus status pill frame the hero.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Animated Gradient Text (Moving Gradient)
Source: https://codefronts.com/motion/tailwind-css-text-gradient/tailwind-animated-gradient-text-moving-gradient/

A hero where colour flows through one word on a perfectly seamless loop. The gradient is a repeating tile twice the element's width, and animate-ttg08-flow moves it exactly one tile per cycle &mdash; fixing the visible jump the CSS original had at the end of every loop. Hover to pause.
## HTML
```html
<section class="ttg-08 relative isolate w-full min-h-svh grid place-items-center overflow-hidden bg-ttg08-bg px-6 py-20 font-ttg08-sans text-ttg08-ink" aria-labelledby="ttg08-title">
  <span aria-hidden="true" class="absolute inset-x-0 top-0 -z-10 h-2/3 bg-[radial-gradient(50%_60%_at_50%_0%,var(--color-ttg08-glow),transparent)]"></span>
  <div class="max-w-3xl text-center">
    <p class="inline-flex items-center gap-2 rounded-full border border-white/10 px-3.5 py-1.5 text-xs font-medium tracking-[0.08em] text-ttg08-mut uppercase"><span aria-hidden="true" class="size-1.5 rounded-full bg-ttg08-c3"></span>Season 3 — now streaming</p>
    <h1 id="ttg08-title" class="mt-7 font-ttg08-display text-[clamp(2.75rem,9vw,6rem)] leading-[1] font-extrabold tracking-[-0.045em]">The future of<br><span class="bg-[linear-gradient(90deg,var(--color-ttg08-c1),var(--color-ttg08-c2),var(--color-ttg08-c3),var(--color-ttg08-c4),var(--color-ttg08-c1))] bg-[length:200%_100%] bg-clip-text pr-[0.04em] text-transparent animate-ttg08-flow hover:[animation-play-state:paused] motion-reduce:animate-none">interface</span> design</h1>
    <p class="mx-auto mt-7 max-w-lg text-[17px]/[1.7] text-ttg08-mut text-pretty">Shifting gradients bring motion and energy to a headline without a single line of JavaScript. Hover the word to freeze it.</p>
    <p aria-hidden="true" class="mt-10 font-mono text-[11.5px] text-ttg08-mut/80">bg-[length:200%_100%] · animate-ttg08-flow · hover:[animation-play-state:paused]</p>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-ttg08-bg: #08080f;
  --color-ttg08-bg: oklch(0.14 0.015 285);
  --color-ttg08-glow: #3b2a6e80;
  --color-ttg08-glow: oklch(0.35 0.11 290 / 0.5);
  --color-ttg08-ink: #f6f7fb;
  --color-ttg08-ink: oklch(0.975 0.005 270);
  --color-ttg08-mut: #a7adbb;
  --color-ttg08-mut: oklch(0.76 0.018 270);
  --color-ttg08-c1: #f39cf5;
  --color-ttg08-c1: oklch(0.8 0.16 325);
  --color-ttg08-c2: #8a8ff9;
  --color-ttg08-c2: oklch(0.69 0.16 280);
  --color-ttg08-c3: #3cc4f5;
  --color-ttg08-c3: oklch(0.77 0.14 225);
  --color-ttg08-c4: #3fdca2;
  --color-ttg08-c4: oklch(0.81 0.15 165);
  --font-ttg08-display: 'Syne', system-ui, sans-serif;
  --font-ttg08-sans: 'Geist', system-ui, sans-serif;
  --animate-ttg08-flow: ttg08-flow 6s linear infinite;

  @keyframes ttg08-flow {
    from {
      background-position: 0% 50%;
    }

    to {
      background-position: 200% 50%;
    }
  }
}

.ttg-08 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

The seamless-loop maths. For a background of width S on a box of width W, a percentage position p offsets the tile by p × (W − S). With S = 2W, moving p from 0% to 200% offsets by exactly −2W — one whole tile — so the last frame equals the first:

--animate-ttg08-flow: ttg08-flow 6s linear infinite;
@keyframes ttg08-flow { to { background-position: 200% 50%; } }

The original animated a 300% gradient from 0% to 100%, which only travels two-thirds of a tile, so every loop snapped back.

Compositor-friendly. Only background-position changes; there is no layout, and the word is short so the repaint area is tiny.

Make it yours

  • Speed: 6s → 3s for energy, 12s for calm.
  • Palette: edit the four --color-ttg08-c* stops; keep the first and last stop equal.
  • Breathing feel: swap linear for ease-in-out (the loop stays seamless).
  • Animate the subtitle too: copy the class list to any span — each element runs its own tile.

Gotchas — read before shipping

  • Keep the background repeating — bg-no-repeat breaks the tile maths and shows a gap at the loop point.
  • If the first and last stops differ, the tile edge shows as a hard seam once per loop.
  • Very long animated strings repaint a larger area each frame; reserve the effect for one display word.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

animation-play-state and background-position animation are universal.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Plain CSSno Tailwind surface

Search CodeFronts

Loading…