← MADLAB / library

MADLAB / TUTORIAL

Build Gradient Text from zero.

A complete, step-by-step breakdown of Gradient Text: from the static contract to a moving gradient clipped to text, responsive behavior, accessibility, and production tuning.

LEVEL / INTERMEDIATETIME / 2–3 HOURSSTACK / REACT + TYPESCRIPT + CSS

00 / Before you code

The mental model.

Gradient Text is a small system: stable structure, explicit state, and one visual rule.

The interaction should earn its cost. If a moving gradient clipped to text is removed, the interface should remain understandable.

01 / Build sequence

From blank file to interaction.

01

Define the component contract.

Write down the smallest public API for Gradient Text. Keep visual decisions in props so the a moving gradient clipped to text can be reused without rewriting the component.

tsx
// Local source: src/ts-tailwind/TextAnimations/GradientText/GradientText.tsx
// Start with the smallest visible version of GradientText.

type GradientTextProps = {
  className?: string;
  color?: string;
};

export function Example({ className, color = "#ff2a2a" }: GradientTextProps) {
  return (
    <div className={className} style={{ color }}>
      {/* Add the Gradient Text behavior here. */}
    </div>
  );
}
02

Build the quiet static state first.

Render the readable fallback before adding motion. The component should still communicate its purpose when JavaScript is delayed or motion is reduced.

03

Normalize the input and measurements.

Clamp numbers, handle an empty value, and measure the real container instead of assuming the viewport. This removes most edge-case bugs before the animation starts.

04

Separate structure from motion.

Keep markup, state, and animation calculations in separate layers. For Gradient Text, the visual structure should remain stable while a moving gradient clipped to text changes over time.

05

Implement the one useful interaction.

Add the core rule only: a moving gradient clipped to text. Use one source of truth for the active value and keep pointer, scroll, or timer listeners passive where possible.

06

Use one animation loop with a clear exit.

Start requestAnimationFrame only when a value changes. Keep the frame id in a ref, interpolate toward the target, and stop when the difference is below a small threshold.

07

Make the layout responsive.

Test narrow mobile widths, wide desktop containers, and text wrapping. Prefer CSS dimensions and ResizeObserver over hard-coded pixels tied to one screenshot.

08

Add reduced-motion and interaction fallbacks.

Respect prefers-reduced-motion and keep a non-motion state. Keyboard focus, readable labels, and a useful static result matter more than a decorative effect.

09

Integrate it into a real section.

Place Gradient Text behind a real message, card, or control. Keep content above decorative layers, preserve the MADBAK palette, and avoid letting motion compete with the hierarchy.

10

Tune, profile, and ship the smallest good version.

Check the effect on a mid-range device, remove unnecessary listeners, and keep the first release focused. Once the behavior is useful, expose only the controls that future projects really need.

02 / Debug checklist

If it feels wrong.

  • The preview is blank: confirm the container has a real height and the client component mounted.
  • It jumps on resize: keep one measured source of truth and cancel stale animation frames.
  • It feels heavy: reduce work per frame, remove duplicate listeners, and stop the loop when idle.
  • It is inaccessible: keep a readable static state, visible focus, and a reduced-motion path.

MADLAB / source

Ready to adapt it?

Open local source ↗