Docs
Animated Gradient Hero

Animated Gradient Hero

A stunning hero section with animated mesh gradients and flowing text effects. Perfect for modern SaaS, tech startups, and premium products. Features smooth canvas animations with warm orange/amber/yellow color scheme.

New: AI-Powered Features

Build faster ship smarter

The complete platform for modern teams. Ship products faster with tools designed for scale and built for the future.

No credit card required
14-day free trial
Cancel anytime
50K+
Active Users
99.9%
Uptime
4.9/5
Rating
4.9/5(2,500+ reviews)

Trusted by teams at

VercelGitHubLinearStripeNotion

Features

  • Fully prop-based - Customize everything via props
  • TypeScript support - Full type safety
  • Animated canvas gradients - Smooth, hardware-accelerated
  • Flowing text gradient - Animated headline effect
  • Floating orb effects - Three independent animations
  • Staggered entrance - Sequential fade-in animations
  • Optional sections - Badge, features, stats, social proof
  • Flexible CTAs - Support for href or onClick
  • Star ratings - Built-in rating display
  • Company logos - Social proof section
  • Fully responsive - Mobile-first design
  • Performance optimized - 60fps animations

Installation

Copy and paste the following code into your project.

"use client";
 
import { Button } from "@/components/ui/button";
import { ArrowRight, CheckCircle2, Play, Sparkles, Star } from "lucide-react";
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
 
interface GradientHeroAnimatedProps {
  badge?: {
    icon?: React.ReactNode;
    text: string;
  };
  headline: {
    line1: string;
    line2: string;
  };
  description: string;
  primaryCTA: {
    text: string;
    href?: string;
    onClick?: () => void;
  };
  secondaryCTA?: {
    text: string;
    href?: string;
    onClick?: () => void;
  };
  features?: string[];
  stats?: Array<{
    value: string;
    label: string;
  }>;
  socialProof?: {
    rating?: number;
    reviewCount?: string;
    text?: string;
    logos?: string[];
  };
  className?: string;
}
 
export function GradientHeroAnimated({
  badge = {
    icon: <Sparkles className="h-3.5 w-3.5" />,
    text: "Introducing our new platform",
  },
  headline = {
    line1: "Build the next",
    line2: "big thing",
  },
  description = "Ship products faster with tools designed for modern teams. From idea to launch in record time.",
  primaryCTA = {
    text: "Get Started Free",
    href: "#",
  },
  secondaryCTA = {
    text: "Watch Demo",
    href: "#",
  },
  features = ["No credit card required", "14-day free trial", "Cancel anytime"],
  stats = [
    { value: "50K+", label: "Active Users" },
    { value: "99.9%", label: "Uptime" },
    { value: "4.9/5", label: "Rating" },
  ],
  socialProof,
  className,
}: GradientHeroAnimatedProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
 
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
 
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
 
    let animationFrameId: number;
    let t = 0;
 
    const resize = () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
    };
 
    window.addEventListener("resize", resize);
    resize();
 
    const animate = () => {
      t += 0.005;
      const w = canvas.width;
      const h = canvas.height;
 
      ctx.clearRect(0, 0, w, h);
 
      // Create a complex mesh gradient effect
      const gradient = ctx.createLinearGradient(0, 0, w, h);
      gradient.addColorStop(0, "#0a0a0a");
      gradient.addColorStop(1, "#171717");
      ctx.fillStyle = gradient;
      ctx.fillRect(0, 0, w, h);
 
      // Organic flowing shapes
      const particles = [
        {
          x: w * 0.2 + Math.sin(t * 0.5) * w * 0.1,
          y: h * 0.2 + Math.cos(t * 0.3) * h * 0.1,
          r: w * 0.4,
          color: "rgba(249, 115, 22, 0.15)", // Orange
        },
        {
          x: w * 0.8 - Math.sin(t * 0.4) * w * 0.1,
          y: h * 0.4 + Math.cos(t * 0.5) * h * 0.1,
          r: w * 0.35,
          color: "rgba(234, 179, 8, 0.12)", // Yellow
        },
        {
          x: w * 0.5 + Math.sin(t * 0.6) * w * 0.15,
          y: h * 0.8 - Math.cos(t * 0.4) * h * 0.1,
          r: w * 0.45,
          color: "rgba(245, 158, 11, 0.1)", // Amber
        },
      ];
 
      particles.forEach((p) => {
        ctx.beginPath();
        const g = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.r);
        g.addColorStop(0, p.color);
        g.addColorStop(1, "rgba(0,0,0,0)");
        ctx.fillStyle = g;
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fill();
      });
 
      // Subtle noise overlay simulation
      ctx.globalCompositeOperation = "overlay";
      ctx.fillStyle = "rgba(255,255,255,0.03)";
      for (let i = 0; i < w; i += 4) {
        for (let j = 0; j < h; j += 4) {
          if (Math.random() > 0.5) {
            ctx.fillRect(i, j, 1, 1);
          }
        }
      }
      ctx.globalCompositeOperation = "source-over";
 
      animationFrameId = requestAnimationFrame(animate);
    };
 
    animate();
 
    return () => {
      window.removeEventListener("resize", resize);
      cancelAnimationFrame(animationFrameId);
    };
  }, []);
 
  return (
    <section
      className={cn(
        "relative min-h-screen w-full overflow-hidden bg-neutral-950 font-sans",
        className,
      )}
    >
      {/* Animated Background */}
      <canvas ref={canvasRef} className="absolute inset-0 h-full w-full" />
 
      {/* Vignette & Overlay */}
      <div className="absolute inset-0 bg-gradient-to-b from-neutral-950/50 via-transparent to-neutral-950 pointer-events-none" />
      <div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 mix-blend-soft-light pointer-events-none" />
 
      <div className="relative z-10 container mx-auto px-4 pt-32 pb-20 md:pt-40 md:pb-32">
        <div className="mx-auto max-w-5xl text-center">
          {/* Badge */}
          {badge && (
            <div className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-1.5 text-sm font-medium text-white/80 backdrop-blur-md transition-all hover:bg-white/10 hover:border-white/20 animate-in fade-in slide-in-from-bottom-4 duration-700 mb-8 cursor-default">
              <span className="flex items-center justify-center rounded-full bg-orange-500/20 p-1 text-orange-400">
                {badge.icon}
              </span>
              {badge.text}
            </div>
          )}
 
          {/* Headline */}
          <h1 className="mx-auto mb-8 max-w-4xl text-5xl font-bold tracking-tight text-white sm:text-7xl md:text-8xl lg:leading-[1.1] animate-in fade-in slide-in-from-bottom-6 duration-1000">
            {headline.line1}{" "}
            <span className="relative whitespace-nowrap">
              <span className="absolute -inset-1 -z-10 block -skew-y-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 blur-xl" />
              <span className="bg-gradient-to-r from-orange-400 via-amber-300 to-yellow-400 bg-clip-text text-transparent">
                {headline.line2}
              </span>
            </span>
          </h1>
 
          {/* Description */}
          <p className="mx-auto mb-12 max-w-2xl text-lg text-neutral-400 sm:text-xl md:text-2xl md:leading-relaxed animate-in fade-in slide-in-from-bottom-8 duration-1000 delay-200">
            {description}
          </p>
 
          {/* CTAs */}
          <div className="flex flex-col items-center justify-center gap-4 sm:flex-row animate-in fade-in slide-in-from-bottom-10 duration-1000 delay-300">
            <Button
              size="lg"
              onClick={
                primaryCTA.onClick ||
                (() =>
                  primaryCTA.href && (window.location.href = primaryCTA.href))
              }
              className="group relative h-14 overflow-hidden rounded-full bg-white px-8 text-lg font-semibold text-neutral-950 transition-all hover:scale-105 hover:bg-neutral-200"
            >
              <span className="relative z-10 flex items-center gap-2">
                {primaryCTA.text}
                <ArrowRight className="h-5 w-5 transition-transform group-hover:translate-x-1" />
              </span>
              <div className="absolute inset-0 -z-10 bg-gradient-to-r from-orange-100 to-amber-100 opacity-0 transition-opacity group-hover:opacity-100" />
            </Button>
 
            {secondaryCTA && (
              <Button
                size="lg"
                variant="ghost"
                onClick={
                  secondaryCTA.onClick ||
                  (() =>
                    secondaryCTA.href &&
                    (window.location.href = secondaryCTA.href))
                }
                className="group h-14 rounded-full border border-white/10 bg-white/5 px-8 text-lg font-semibold text-white backdrop-blur-sm transition-all hover:bg-white/10 hover:border-white/20"
              >
                <Play className="mr-2 h-5 w-5 fill-white/20 transition-transform group-hover:scale-110" />
                {secondaryCTA.text}
              </Button>
            )}
          </div>
 
          {/* Features */}
          {features && features.length > 0 && (
            <div className="mt-12 flex flex-wrap justify-center gap-x-8 gap-y-4 text-sm text-neutral-500 animate-in fade-in slide-in-from-bottom-12 duration-1000 delay-400">
              {features.map((feature, i) => (
                <div key={i} className="flex items-center gap-2">
                  <CheckCircle2 className="h-4 w-4 text-orange-500" />
                  <span>{feature}</span>
                </div>
              ))}
            </div>
          )}
 
          {/* Social Proof & Stats */}
          {stats && stats.length > 0 && (
            <div className="mt-24 border-t border-white/5 pt-12 animate-in fade-in slide-in-from-bottom-12 duration-1000 delay-500">
              <div className="grid grid-cols-3 gap-8 text-center">
                {stats.map((stat, i) => (
                  <div key={i} className="group">
                    <div className="text-3xl font-bold text-white transition-colors group-hover:text-orange-400">
                      {stat.value}
                    </div>
                    <div className="text-sm font-medium text-neutral-500">
                      {stat.label}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )}
 
          {/* Social Proof */}
          {socialProof && (
            <div className="mt-16 space-y-8 animate-in fade-in slide-in-from-bottom-12 duration-1000 delay-600">
              {(socialProof.rating || socialProof.text) && (
                <div className="flex flex-col items-center gap-3">
                  {socialProof.rating && (
                    <div className="flex items-center gap-2">
                      <div className="flex">
                        {[...Array(5)].map((_, i) => (
                          <Star
                            key={i}
                            className={cn(
                              "h-4 w-4",
                              i < Math.floor(socialProof.rating!)
                                ? "fill-orange-500 text-orange-500"
                                : "fill-neutral-800 text-neutral-800",
                            )}
                          />
                        ))}
                      </div>
                      <span className="text-sm font-medium text-white">
                        {socialProof.rating}/5
                      </span>
                      {socialProof.reviewCount && (
                        <span className="text-sm text-neutral-500">
                          ({socialProof.reviewCount} reviews)
                        </span>
                      )}
                    </div>
                  )}
                  {socialProof.text && (
                    <p className="text-xs text-neutral-500 uppercase tracking-widest">
                      {socialProof.text}
                    </p>
                  )}
                </div>
              )}
 
              {socialProof.logos && socialProof.logos.length > 0 && (
                <div className="flex flex-wrap items-center justify-center gap-8 opacity-40 grayscale transition-all duration-500 hover:opacity-100 hover:grayscale-0">
                  {socialProof.logos.map((logo, i) => (
                    <span key={i} className="text-lg font-bold text-white">
                      {logo}
                    </span>
                  ))}
                </div>
              )}
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

Update the import paths to match your project setup.

import { Button } from "@/components/ui/button";

Usage

Basic Usage

import GradientHeroAnimated from "@/components/ui/gradient-hero-animated";
 
export default function HomePage() {
  return <GradientHeroAnimated />;
}

With Custom Props

import GradientHeroAnimated from "@/components/ui/gradient-hero-animated";
import { Sparkles } from "lucide-react";
 
export default function HomePage() {
  return (
    <GradientHeroAnimated
      badge={{
        icon: <Sparkles className="h-4 w-4" />,
        text: "New: AI-Powered Features",
      }}
      headline={{
        line1: "Build faster",
        line2: "ship smarter",
      }}
      description="The complete platform for modern teams. Ship products faster with tools designed for scale."
      primaryCTA={{
        text: "Start Free Trial",
        onClick: () => console.log("Primary CTA clicked"),
      }}
      secondaryCTA={{
        text: "Watch Demo",
        href: "/demo",
      }}
      features={[
        "No credit card required",
        "14-day free trial",
        "Cancel anytime",
      ]}
      stats={[
        { value: "100K+", label: "Active Users" },
        { value: "99.9%", label: "Uptime" },
        { value: "4.9/5", label: "Rating" },
      ]}
      socialProof={{
        rating: 4.9,
        reviewCount: "2,500+",
        text: "Trusted by teams worldwide",
        logos: ["Google", "Microsoft", "Amazon", "Netflix"],
      }}
    />
  );
}

With Router Navigation

"use client";
 
import { useRouter } from "next/navigation";
import GradientHeroAnimated from "@/components/ui/gradient-hero-animated";
 
export default function HomePage() {
  const router = useRouter();
 
  return (
    <GradientHeroAnimated
      headline={{
        line1: "Build the next",
        line2: "big thing",
      }}
      description="Ship products faster with tools designed for modern teams."
      primaryCTA={{
        text: "Get Started Free",
        onClick: () => router.push("/signup"),
      }}
      secondaryCTA={{
        text: "Learn More",
        onClick: () => router.push("/about"),
      }}
    />
  );
}

Props

GradientHeroAnimatedProps

PropTypeDefaultDescription
badgeobject{ icon: <Sparkles />, text: "Introducing our new platform" }Optional badge at the top
badge.iconReact.ReactNode<Sparkles />Icon for the badge
badge.textstringRequiredBadge text
headlineobject{ line1: "Build the next", line2: "big thing" }Headline configuration
headline.line1stringRequiredFirst line of headline
headline.line2stringRequiredSecond line (gets animated gradient)
descriptionstringDefault textHero description
primaryCTAobjectRequiredPrimary call-to-action button
primaryCTA.textstringRequiredButton text
primaryCTA.hrefstringOptionalLink URL
primaryCTA.onClick() => voidOptionalClick handler
secondaryCTAobjectOptionalSecondary call-to-action button
secondaryCTA.textstringRequiredButton text
secondaryCTA.hrefstringOptionalLink URL
secondaryCTA.onClick() => voidOptionalClick handler
featuresstring[]["No credit card required", ...]Feature list with checkmarks
statsArray<{value: string, label: string}>Default statsStats to display
socialProofobjectOptionalSocial proof section
socialProof.ratingnumberOptionalStar rating (0-5)
socialProof.reviewCountstringOptionalNumber of reviews
socialProof.textstringOptionalSocial proof text
socialProof.logosstring[]OptionalCompany logos

Customization

Minimal Example

<GradientHeroAnimated
  headline={{
    line1: "Simple",
    line2: "and clean",
  }}
  description="Less is more."
  primaryCTA={{
    text: "Get Started",
    href: "/signup",
  }}
  features={undefined}
  stats={undefined}
  socialProof={undefined}
/>

With All Features

<GradientHeroAnimated
  badge={{ text: "🎉 Product Hunt #1 Product of the Day" }}
  headline={{
    line1: "The future of",
    line2: "productivity",
  }}
  description="Everything you need to build, ship, and scale your product. Trusted by over 50,000 teams worldwide."
  primaryCTA={{
    text: "Start Free Trial",
    onClick: handleSignup,
  }}
  secondaryCTA={{
    text: "Schedule Demo",
    onClick: handleDemo,
  }}
  features={[
    "Free 14-day trial",
    "No credit card required",
    "Cancel anytime",
    "24/7 support",
  ]}
  stats={[
    { value: "50K+", label: "Active Users" },
    { value: "99.9%", label: "Uptime SLA" },
    { value: "4.9/5", label: "User Rating" },
  ]}
  socialProof={{
    rating: 4.9,
    reviewCount: "5,000+",
    text: "Loved by teams at",
    logos: ["Stripe", "Vercel", "Linear", "GitHub", "Notion"],
  }}
/>

Change Gradient Colors

To change the animated gradient colors, you'll need to modify the canvas gradient stops in the component. Here are some preset color schemes:

Orange/Amber/Yellow (Default):

gradient1.addColorStop(0, "rgba(251, 146, 60, 0.35)");
gradient2.addColorStop(0, "rgba(245, 158, 11, 0.4)");
gradient3.addColorStop(0, "rgba(250, 204, 21, 0.3)");

Purple/Pink/Blue:

gradient1.addColorStop(0, "rgba(139, 92, 246, 0.35)");
gradient2.addColorStop(0, "rgba(236, 72, 153, 0.4)");
gradient3.addColorStop(0, "rgba(59, 130, 246, 0.3)");

Green/Teal/Cyan:

gradient1.addColorStop(0, "rgba(16, 185, 129, 0.35)");
gradient2.addColorStop(0, "rgba(20, 184, 166, 0.4)");
gradient3.addColorStop(0, "rgba(6, 182, 212, 0.3)");

Red/Orange/Pink:

gradient1.addColorStop(0, "rgba(239, 68, 68, 0.35)");
gradient2.addColorStop(0, "rgba(249, 115, 22, 0.4)");
gradient3.addColorStop(0, "rgba(236, 72, 153, 0.3)");

Best Practices

  1. Color contrast - Ensure text remains readable against animated backgrounds
  2. Performance testing - Test on lower-end devices, consider reducing animation complexity for mobile
  3. Blur intensity - Adjust blur values if gradients are too intense or subtle
  4. Animation speed - Slower animations (15-20s) feel more premium than fast ones
  5. Content hierarchy - Keep the layout clean and focused on the main message

Use Cases

Perfect for:

  • Modern SaaS platforms
  • Tech startups
  • AI/ML products
  • Creative tools
  • Design software
  • Developer platforms
  • Premium services
  • Product launches

Examples

Similar styles used by:

  • Vercel - Deployment platform with animated gradients
  • Stripe - Payment platform with elegant animations
  • Linear - Issue tracking with smooth transitions
  • Framer - Design tool with flowing gradients

TypeScript Interface

interface GradientHeroAnimatedProps {
  badge?: {
    icon?: React.ReactNode;
    text: string;
  };
  headline: {
    line1: string;
    line2: string; // This line gets the animated gradient
  };
  description: string;
  primaryCTA: {
    text: string;
    href?: string;
    onClick?: () => void;
  };
  secondaryCTA?: {
    text: string;
    href?: string;
    onClick?: () => void;
  };
  features?: string[];
  stats?: Array<{
    value: string;
    label: string;
  }>;
  socialProof?: {
    rating?: number;
    reviewCount?: string;
    text?: string;
    logos?: string[];
  };
}
@media (prefers-reduced-motion: reduce) {
  .animate-gradient,
  .animate-float,
  .animate-float-delayed,
  .animate-float-slow {
    animation: none;
  }
}