Docs
Hero Video Background

Hero Video Background

A stunning full-screen hero section with video background and overlay text. Features autoplay, video controls, and customizable overlay opacity.

Experience the Future

Transform your business with cutting-edge technology and innovative solutions

Dive Into Innovation

Discover powerful tools designed to elevate your workflow

Build Something Amazing

Join thousands of teams already using our platform

Why Choose Us

Trusted by industry leaders worldwide

Features

  • Full-screen video - Immersive background experience
  • Autoplay - Starts automatically on load
  • Video controls - Play/pause and mute/unmute buttons
  • Customizable overlay - Adjustable darkness level
  • Dual CTAs - Primary and secondary action buttons
  • Scroll indicator - Animated bounce effect
  • Responsive - Works on all screen sizes
  • Mobile optimized - Uses playsInline for iOS
  • Hover effects - Scale animations on buttons
  • TypeScript support - Full type safety

Installation

Copy and paste the following code into your project.

"use client";
 
import { useState, useRef, useEffect } from "react";
import { Play, Pause, Volume2, VolumeX } from "lucide-react";
 
interface HeroVideoBackgroundProps {
  videoUrl?: string;
  title: string;
  description: string;
  primaryCTA?: {
    text: string;
    href: string;
  };
  secondaryCTA?: {
    text: string;
    href: string;
  };
  showControls?: boolean;
  overlayOpacity?: number;
  className?: string;
}
 
export function HeroVideoBackground({
  videoUrl = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
  title,
  description,
  primaryCTA,
  secondaryCTA,
  showControls = true,
  overlayOpacity = 0.6,
  className = "",
}: HeroVideoBackgroundProps) {
  const [isPlaying, setIsPlaying] = useState(true);
  const [isMuted, setIsMuted] = useState(true);
  const videoRef = useRef<HTMLVideoElement>(null);
 
  useEffect(() => {
    if (videoRef.current) {
      videoRef.current.play().catch(() => {
        setIsPlaying(false);
      });
    }
  }, []);
 
  const togglePlay = () => {
    if (videoRef.current) {
      if (isPlaying) {
        videoRef.current.pause();
      } else {
        videoRef.current.play();
      }
      setIsPlaying(!isPlaying);
    }
  };
 
  const toggleMute = () => {
    if (videoRef.current) {
      videoRef.current.muted = !isMuted;
      setIsMuted(!isMuted);
    }
  };
 
  return (
    <section
      className={`relative flex min-h-screen items-center justify-center rounded overflow-hidden ${className}`}
    >
      <video
        ref={videoRef}
        autoPlay
        loop
        muted
        playsInline
        className="absolute inset-0 h-full w-full object-cover"
      >
        <source src={videoUrl} type="video/mp4" />
      </video>
 
      <div
        className="absolute inset-0 bg-black"
        style={{ opacity: overlayOpacity }}
      />
 
      <div className="relative z-10 mx-auto max-w-5xl px-4 text-center sm:px-6 lg:px-8">
        <h1 className="mb-6 text-5xl font-bold leading-tight text-white sm:text-6xl lg:text-7xl">
          {title}
        </h1>
        <p className="mb-10 text-xl text-zinc-300 sm:text-2xl lg:text-3xl">
          {description}
        </p>
 
        {(primaryCTA || secondaryCTA) && (
          <div className="flex flex-col items-center justify-center gap-4 sm:flex-row">
            {primaryCTA && (
              <a
                href={primaryCTA.href}
                className="inline-flex items-center gap-2 rounded-lg bg-orange-600 px-8 py-4 text-lg font-semibold text-white transition-all hover:bg-orange-700 hover:scale-105"
              >
                {primaryCTA.text}
              </a>
            )}
            {secondaryCTA && (
              <a
                href={secondaryCTA.href}
                className="inline-flex items-center gap-2 rounded-lg border-2 border-white bg-white/10 px-8 py-4 text-lg font-semibold text-white backdrop-blur-sm transition-all hover:bg-white/20 hover:scale-105"
              >
                {secondaryCTA.text}
              </a>
            )}
          </div>
        )}
      </div>
 
      {showControls && (
        <div className="absolute bottom-8 right-8 z-20 flex gap-2">
          <button
            onClick={togglePlay}
            className="rounded-lg bg-black/50 p-3 text-white backdrop-blur-sm transition-all hover:bg-black/70"
            aria-label={isPlaying ? "Pause video" : "Play video"}
          >
            {isPlaying ? (
              <Pause className="h-5 w-5" />
            ) : (
              <Play className="h-5 w-5" />
            )}
          </button>
          <button
            onClick={toggleMute}
            className="rounded-lg bg-black/50 p-3 text-white backdrop-blur-sm transition-all hover:bg-black/70"
            aria-label={isMuted ? "Unmute video" : "Mute video"}
          >
            {isMuted ? (
              <VolumeX className="h-5 w-5" />
            ) : (
              <Volume2 className="h-5 w-5" />
            )}
          </button>
        </div>
      )}
 
      <div className="absolute bottom-8 left-1/2 z-10 -translate-x-1/2 animate-bounce">
        <div className="flex h-12 w-8 items-start justify-center rounded-full border-2 border-white/50 p-2">
          <div className="h-2 w-1 animate-pulse rounded-full bg-white" />
        </div>
      </div>
    </section>
  );
}

Usage

Basic Usage

import HeroVideoBackground from "@/components/ui/hero-video-background";
 
export default function Page() {
  return (
    <HeroVideoBackground
      title="Experience the Future"
      description="Transform your business with cutting-edge technology"
      primaryCTA={{
        text: "Get Started",
        href: "/signup",
      }}
      secondaryCTA={{
        text: "Watch Demo",
        href: "/demo",
      }}
    />
  );
}

Custom Video URL

<HeroVideoBackground
  videoUrl="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
  title="Your Title"
  description="Your description"
  primaryCTA={{
    text: "Get Started",
    href: "#",
  }}
/>

Adjust Overlay Opacity

<HeroVideoBackground
  title="Lighter Overlay"
  description="More visible video background"
  overlayOpacity={0.4} // 0 = transparent, 1 = fully dark
  primaryCTA={{
    text: "Get Started",
    href: "#",
  }}
/>

Without Video Controls

<HeroVideoBackground
  title="Clean Look"
  description="No video controls visible"
  showControls={false}
  primaryCTA={{
    text: "Get Started",
    href: "#",
  }}
/>

Single CTA

<HeroVideoBackground
  title="Simple Hero"
  description="Just one call to action"
  primaryCTA={{
    text: "Get Started",
    href: "#",
  }}
  // No secondaryCTA
/>

Props

HeroVideoBackgroundProps

PropTypeDefaultDescription
videoUrlstringGoogle sample videoVideo source URL
titlestringRequiredMain heading text
descriptionstringRequiredSubheading text
primaryCTA{ text: string; href: string }undefinedPrimary button
secondaryCTA{ text: string; href: string }undefinedSecondary button
showControlsbooleantrueShow video controls
overlayOpacitynumber0.6Overlay darkness (0-1)
classNamestring""Additional CSS classes

TypeScript Interface

interface HeroVideoBackgroundProps {
  videoUrl?: string;
  title: string;
  description: string;
  primaryCTA?: {
    text: string;
    href: string;
  };
  secondaryCTA?: {
    text: string;
    href: string;
  };
  showControls?: boolean;
  overlayOpacity?: number;
  className?: string;
}

Video Sources

Working Test Videos

For testing and demos, use these reliable sources:

  • Google Cloud Storage - https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/
    • BigBuckBunny.mp4
    • ElephantsDream.mp4
    • ForBiggerBlazes.mp4
    • Sintel.mp4

Free Video Resources (Download & Self-Host)

For production, download videos and host them yourself:

Important: Many free video sites block hotlinking. Always download and host videos on your own server or CDN.

Use Cases

Perfect for:

  • Landing pages
  • Product launches
  • Brand showcases
  • Event promotions
  • Portfolio sites
  • Agency websites
  • SaaS homepages
  • Marketing campaigns

Customization

Add Gradient Overlay

<div className="absolute inset-0 bg-gradient-to-b from-black/50 via-black/60 to-black/80" />

Add Animated Text

<h1 className="mb-6 animate-fade-in text-5xl font-bold">
  {title}
</h1>

Add Stats or Features

<div className="mt-12 grid grid-cols-3 gap-8">
  <div>
    <div className="text-4xl font-bold text-white">10K+</div>
    <div className="text-zinc-400">Users</div>
  </div>
  {/* More stats */}
</div>

Custom Scroll Indicator

<div className="absolute bottom-8 left-1/2 -translate-x-1/2">
  <ChevronDown className="h-8 w-8 animate-bounce text-white" />
</div>