Docs
Hero Split Screen

Hero Split Screen

A modern SaaS hero with animated dashboard visuals. Features floating cards, metrics, grid patterns, and multiple color themes.

Trusted by 50,000+ teams

Ship products faster with confidence

The modern platform that helps teams build, deploy, and scale applications without the complexity

99.9%
Uptime
50ms
Response
2.4M
Users
Enterprise Ready

Scale without limits

Built for performance, designed for growth. Handle millions of requests with ease

10x
Faster
256-bit
Secure
24/7
Support
AI Powered

Intelligent automation at scale

Let AI handle the heavy lifting while you focus on what matters most

Developer First

Built for modern workflows

Powerful APIs, comprehensive docs, and tools that developers love

100+
Integrations
<100ms
API Speed
5min
Setup

Features

  • Animated visuals - Floating cards, metrics, and grid patterns
  • Multiple themes - Blue, purple, emerald, and cyan color schemes
  • 3 visual types - Dashboard, metrics, and grid layouts
  • Stats display - Show key metrics in a grid
  • Gradient text - Modern gradient heading
  • Badge support - Sparkle icon with custom text
  • Dual CTAs - Primary with arrow and secondary
  • Glow effects - Subtle background glows
  • Responsive - Hides visual on mobile
  • TypeScript support - Full type safety

Installation

Copy and paste the following code into your project.

"use client";
 
import { useState, useEffect } from "react";
import { ArrowRight, Sparkles, Zap, Shield, TrendingUp } from "lucide-react";
 
interface Stat {
  value: string;
  label: string;
}
 
interface HeroSplitScreenProps {
  badge?: string;
  title: string;
  description: string;
  stats?: Stat[];
  primaryCTA?: {
    text: string;
    href: string;
  };
  secondaryCTA?: {
    text: string;
    href: string;
  };
  visualType?: "dashboard" | "metrics" | "grid";
  accentColor?: "blue" | "purple" | "emerald" | "cyan";
  className?: string;
}
 
const colorSchemes = {
  blue: {
    primary: "from-blue-500 to-cyan-500",
    glow: "bg-blue-500/20",
    border: "border-blue-500/30",
    text: "text-blue-400",
    button: "bg-blue-600 hover:bg-blue-700",
  },
  purple: {
    primary: "from-purple-500 to-pink-500",
    glow: "bg-purple-500/20",
    border: "border-purple-500/30",
    text: "text-purple-400",
    button: "bg-purple-600 hover:bg-purple-700",
  },
  emerald: {
    primary: "from-emerald-500 to-teal-500",
    glow: "bg-emerald-500/20",
    border: "border-emerald-500/30",
    text: "text-emerald-400",
    button: "bg-emerald-600 hover:bg-emerald-700",
  },
  cyan: {
    primary: "from-cyan-500 to-blue-500",
    glow: "bg-cyan-500/20",
    border: "border-cyan-500/30",
    text: "text-cyan-400",
    button: "bg-cyan-600 hover:bg-cyan-700",
  },
};
 
export function HeroSplitScreen({
  badge,
  title,
  description,
  stats,
  primaryCTA,
  secondaryCTA,
  visualType = "dashboard",
  accentColor = "blue",
  className = "",
}: HeroSplitScreenProps) {
  const [activeMetric, setActiveMetric] = useState(0);
  const colors = colorSchemes[accentColor];
 
  useEffect(() => {
    const interval = setInterval(() => {
      setActiveMetric((prev) => (prev + 1) % 3);
    }, 2000);
    return () => clearInterval(interval);
  }, []);
 
  const DashboardVisual = () => (
    <div className="relative h-full w-full">
      <div className="absolute inset-0 bg-[linear-gradient(to_right,#1f1f1f_1px,transparent_1px),linear-gradient(to_bottom,#1f1f1f_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_80%_50%_at_50%_50%,#000_70%,transparent_100%)]" />
 
      <div className="absolute inset-0 flex items-center justify-center p-8">
        <div className="relative w-full max-w-md space-y-4">
          <div className="animate-float rounded-2xl border border-zinc-800 bg-zinc-950/90 p-6 backdrop-blur-xl">
            <div className="mb-4 flex items-center justify-between">
              <div className={`rounded-lg ${colors.glow} p-2`}>
                <TrendingUp className={`h-5 w-5 ${colors.text}`} />
              </div>
              <span className="text-2xl font-bold text-white">+24%</span>
            </div>
            <div className="h-2 w-full rounded-full bg-zinc-800">
              <div
                className={`h-full rounded-full bg-gradient-to-r ${colors.primary} transition-all duration-1000`}
                style={{ width: "75%" }}
              />
            </div>
          </div>
 
          <div
            className="animate-float rounded-2xl border border-zinc-800 bg-zinc-950/90 p-6 backdrop-blur-xl"
            style={{ animationDelay: "0.5s" }}
          >
            <div className="mb-4 flex items-center justify-between">
              <div className={`rounded-lg ${colors.glow} p-2`}>
                <Zap className={`h-5 w-5 ${colors.text}`} />
              </div>
              <span className="text-2xl font-bold text-white">98.5%</span>
            </div>
            <div className="flex gap-1">
              {Array.from({ length: 12 }).map((_, i) => (
                <div
                  key={i}
                  className={`h-12 flex-1 rounded ${
                    i < 10
                      ? `bg-gradient-to-t ${colors.primary}`
                      : "bg-zinc-800"
                  }`}
                  style={{
                    height: `${Math.random() * 40 + 20}px`,
                  }}
                />
              ))}
            </div>
          </div>
 
          <div
            className="animate-float rounded-2xl border border-zinc-800 bg-zinc-950/90 p-6 backdrop-blur-xl"
            style={{ animationDelay: "1s" }}
          >
            <div className="flex items-center gap-4">
              <div className={`rounded-lg ${colors.glow} p-2`}>
                <Shield className={`h-5 w-5 ${colors.text}`} />
              </div>
              <div className="flex-1">
                <div className="mb-2 text-sm text-zinc-400">Security Score</div>
                <div className="flex items-center gap-2">
                  <div className="h-2 flex-1 rounded-full bg-zinc-800">
                    <div
                      className={`h-full rounded-full bg-gradient-to-r ${colors.primary}`}
                      style={{ width: "92%" }}
                    />
                  </div>
                  <span className="text-sm font-semibold text-white">92</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
 
      <div
        className={`absolute left-1/2 top-1/2 h-96 w-96 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gradient-to-r ${colors.primary} opacity-20 blur-3xl`}
      />
    </div>
  );
 
  const MetricsVisual = () => (
    <div className="relative h-full w-full">
      <div className="absolute inset-0 flex items-center justify-center p-8">
        <div className="grid w-full max-w-md grid-cols-2 gap-4">
          {[
            {
              icon: TrendingUp,
              value: "2.4M",
              label: "Active Users",
              index: 0,
            },
            { icon: Zap, value: "99.9%", label: "Uptime", index: 1 },
            { icon: Shield, value: "256-bit", label: "Encryption", index: 2 },
            { icon: Sparkles, value: "50ms", label: "Response", index: 2 },
          ].map((metric, i) => (
            <div
              key={i}
              className={`rounded-2xl border ${
                activeMetric === metric.index
                  ? colors.border
                  : "border-zinc-800"
              } bg-zinc-950/90 p-6 backdrop-blur-xl transition-all duration-500 ${
                activeMetric === metric.index ? "scale-105" : ""
              }`}
            >
              <div className={`mb-4 rounded-lg ${colors.glow} inline-flex p-3`}>
                <metric.icon className={`h-6 w-6 ${colors.text}`} />
              </div>
              <div className="mb-1 text-3xl font-bold text-white">
                {metric.value}
              </div>
              <div className="text-sm text-zinc-400">{metric.label}</div>
            </div>
          ))}
        </div>
      </div>
      <div
        className={`absolute left-1/2 top-1/2 h-96 w-96 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gradient-to-r ${colors.primary} opacity-20 blur-3xl`}
      />
    </div>
  );
 
  const GridVisual = () => (
    <div className="relative h-full w-full overflow-hidden">
      <div className="absolute inset-0 grid grid-cols-8 grid-rows-8 gap-2 p-8">
        {Array.from({ length: 64 }).map((_, i) => (
          <div
            key={i}
            className={`rounded-lg ${
              Math.random() > 0.7
                ? `bg-gradient-to-br ${colors.primary} opacity-50`
                : "bg-zinc-900"
            } transition-all duration-1000`}
            style={{
              animationDelay: `${i * 0.02}s`,
            }}
          />
        ))}
      </div>
      <div
        className={`absolute left-1/2 top-1/2 h-96 w-96 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gradient-to-r ${colors.primary} opacity-20 blur-3xl`}
      />
    </div>
  );
 
  const visuals = {
    dashboard: <DashboardVisual />,
    metrics: <MetricsVisual />,
    grid: <GridVisual />,
  };
 
  return (
    <section className={`min-h-screen bg-black ${className}`}>
      <div className="grid min-h-screen lg:grid-cols-2">
        <div className="flex items-center px-6 py-12 sm:px-12 lg:px-16">
          <div className="w-full max-w-xl">
            {badge && (
              <div
                className={`mb-6 inline-flex items-center gap-2 rounded-full border ${colors.border} ${colors.glow} px-4 py-2 text-sm font-medium ${colors.text}`}
              >
                <Sparkles className="h-4 w-4" />
                {badge}
              </div>
            )}
 
            <h1 className="mb-6 bg-gradient-to-br from-white to-zinc-400 bg-clip-text text-5xl font-bold leading-tight text-transparent lg:text-6xl">
              {title}
            </h1>
 
            <p className="mb-8 text-xl text-zinc-400 lg:text-2xl">
              {description}
            </p>
 
            {stats && stats.length > 0 && (
              <div className="mb-8 grid grid-cols-3 gap-6">
                {stats.map((stat, index) => (
                  <div key={index}>
                    <div className="mb-1 text-3xl font-bold text-white">
                      {stat.value}
                    </div>
                    <div className="text-sm text-zinc-500">{stat.label}</div>
                  </div>
                ))}
              </div>
            )}
 
            {(primaryCTA || secondaryCTA) && (
              <div className="flex flex-col gap-4 sm:flex-row">
                {primaryCTA && (
                  <a
                    href={primaryCTA.href}
                    className={`group inline-flex items-center justify-center gap-2 rounded-lg ${colors.button} px-8 py-4 text-lg font-semibold text-white transition-all hover:scale-105`}
                  >
                    {primaryCTA.text}
                    <ArrowRight className="h-5 w-5 transition-transform group-hover:translate-x-1" />
                  </a>
                )}
                {secondaryCTA && (
                  <a
                    href={secondaryCTA.href}
                    className="inline-flex items-center justify-center gap-2 rounded-lg border-2 border-zinc-700 px-8 py-4 text-lg font-semibold text-white transition-all hover:border-zinc-600 hover:bg-zinc-900"
                  >
                    {secondaryCTA.text}
                  </a>
                )}
              </div>
            )}
          </div>
        </div>
 
        <div className="relative hidden lg:block">{visuals[visualType]}</div>
      </div>
 
      <style jsx>{`
        @keyframes float {
          0%,
          100% {
            transform: translateY(0px);
          }
          50% {
            transform: translateY(-20px);
          }
        }
        .animate-float {
          animation: float 6s ease-in-out infinite;
        }
      `}</style>
    </section>
  );
}

Usage

Basic Usage

import HeroSplitScreen from "@/components/ui/hero-split-screen";
 
export default function Page() {
  return (
    <HeroSplitScreen
      title="Ship products faster"
      description="The modern platform for building applications"
      primaryCTA={{
        text: "Get Started",
        href: "/signup",
      }}
    />
  );
}

With Stats

<HeroSplitScreen
  title="Your Title"
  description="Your description"
  stats={[
    { value: "99.9%", label: "Uptime" },
    { value: "50ms", label: "Response" },
    { value: "2.4M", label: "Users" },
  ]}
  primaryCTA={{
    text: "Get Started",
    href: "#",
  }}
/>

Different Visual Types

// Dashboard with floating cards
<HeroSplitScreen
  visualType="dashboard"
  accentColor="blue"
  // ... other props
/>
 
// Metrics grid
<HeroSplitScreen
  visualType="metrics"
  accentColor="purple"
  // ... other props
/>
 
// Animated grid pattern
<HeroSplitScreen
  visualType="grid"
  accentColor="emerald"
  // ... other props
/>

Color Themes

// Blue theme
<HeroSplitScreen accentColor="blue" {...props} />
 
// Purple theme
<HeroSplitScreen accentColor="purple" {...props} />
 
// Emerald theme
<HeroSplitScreen accentColor="emerald" {...props} />
 
// Cyan theme
<HeroSplitScreen accentColor="cyan" {...props} />

With Badge

<HeroSplitScreen
  badge="Trusted by 50,000+ teams"
  title="Your Title"
  description="Your description"
  primaryCTA={{
    text: "Get Started",
    href: "#",
  }}
/>

Props

HeroSplitScreenProps

PropTypeDefaultDescription
titlestringRequiredMain heading text
descriptionstringRequiredSubheading text
badgestringundefinedOptional top badge
statsStat[]undefinedStats grid (3 items)
primaryCTA{ text: string; href: string }undefinedPrimary button
secondaryCTA{ text: string; href: string }undefinedSecondary button
visualType"dashboard" | "metrics" | "grid""dashboard"Visual style
accentColor"blue" | "purple" | "emerald" | "cyan""blue"Color theme
classNamestring""Additional CSS classes

Stat

PropTypeRequiredDescription
valuestringYesStat value (e.g., "99.9%")
labelstringYesStat label (e.g., "Uptime")

TypeScript Interface

interface Stat {
  value: string;
  label: string;
}
 
interface HeroSplitScreenProps {
  badge?: string;
  title: string;
  description: string;
  stats?: Stat[];
  primaryCTA?: {
    text: string;
    href: string;
  };
  secondaryCTA?: {
    text: string;
    href: string;
  };
  visualType?: "dashboard" | "metrics" | "grid";
  accentColor?: "blue" | "purple" | "emerald" | "cyan";
  className?: string;
}

Use Cases

Perfect for:

  • SaaS landing pages
  • Product launches
  • Platform homepages
  • Developer tools
  • Analytics dashboards
  • AI/ML products
  • API services
  • Enterprise software

Customization

Add More Metrics

// In MetricsVisual, add more items to the array
{ icon: YourIcon, value: "Value", label: "Label", index: 3 }

Change Animation Speed

// Adjust the interval in useEffect
setInterval(() => {
  setActiveMetric((prev) => (prev + 1) % 3);
}, 3000); // Change from 2000 to 3000

Custom Gradient

// Add to colorSchemes object
custom: {
  primary: "from-red-500 to-orange-500",
  glow: "bg-red-500/20",
  border: "border-red-500/30",
  text: "text-red-400",
  button: "bg-red-600 hover:bg-red-700",
}

Remove Grid Background

// Remove this div from DashboardVisual
<div className="absolute inset-0 bg-[linear-gradient...]" />