Innovations

Gated Download Card

Lead magnet card with email gate in front of a download. Lists what\

Preview

Source

tsx
"use client";

import { useState } from "react";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  FileText,
  Download,
  CheckCircle,
  ArrowRight,
  Lock,
} from "lucide-react";

const included = [
  "47-page step-by-step playbook (PDF)",
  "Revenue projection spreadsheet template",
  "Email sequences that convert (12 proven templates)",
  "Onboarding checklist for new clients",
];

export default function GatedDownload() {
  const [email, setEmail] = useState("");
  const [submitted, setSubmitted] = useState(false);

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!email) return;
    setSubmitted(true);
  }

  return (
    <div className="flex min-h-[400px] items-center justify-center bg-background p-8">
      <Card className="w-full max-w-md overflow-hidden shadow-xl border-border">
        {/* Colored top accent */}
        <div className="h-2 w-full bg-gradient-to-r from-violet-500 to-purple-600" />

        <CardHeader className="pt-6 pb-0 px-6">
          {/* Icon + label */}
          <div className="flex items-center gap-3 mb-4">
            <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-violet-100 text-violet-600">
              <FileText className="h-6 w-6" />
            </div>
            <div>
              <p className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
                Free download
              </p>
              <h2 className="text-lg font-extrabold text-foreground leading-tight">
                The Growth Playbook 2025
              </h2>
            </div>
          </div>

          <p className="text-sm text-muted-foreground leading-relaxed">
            Everything you need to take a client from zero to $100K/month — templates,
            frameworks, and the exact playbook our team uses every day.
          </p>
        </CardHeader>

        <CardContent className="px-6 pb-6 pt-5">
          {/* What's included */}
          <div className="mb-5 space-y-2">
            <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">
              What's inside
            </p>
            {included.map((item) => (
              <div key={item} className="flex items-start gap-2 text-sm text-foreground">
                <CheckCircle className="h-4 w-4 text-violet-500 mt-0.5 shrink-0" />
                <span>{item}</span>
              </div>
            ))}
          </div>

          {submitted ? (
            <div className="space-y-4 text-center py-2">
              <div className="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-green-100 text-green-600">
                <CheckCircle className="h-7 w-7" />
              </div>
              <div>
                <h3 className="font-bold text-base text-foreground">Access unlocked!</h3>
                <p className="text-sm text-muted-foreground mt-1">
                  Check <strong>{email}</strong> for your download link.
                </p>
              </div>
              <Button className="w-full gap-2" asChild>
                <a href="#" download>
                  <Download className="h-4 w-4" />
                  Download now
                </a>
              </Button>
            </div>
          ) : (
            <form onSubmit={handleSubmit} className="space-y-3">
              <div className="relative">
                <Lock className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
                <Input
                  type="email"
                  placeholder="Enter email to unlock"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  required
                  className="pl-9 h-11"
                />
              </div>
              <Button type="submit" className="w-full h-11 gap-2 font-semibold bg-violet-600 hover:bg-violet-700 text-white">
                Unlock free download
                <ArrowRight className="h-4 w-4" />
              </Button>
              <p className="text-center text-xs text-muted-foreground">
                No credit card · No spam · Instant access
              </p>
            </form>
          )}
        </CardContent>
      </Card>
    </div>
  );
}
Claude Code Instructions

CLI Install

npx innovations add gated-download

Where to use it

Embed on blog posts, landing pages, or resource pages to capture leads in exchange for a downloadable asset. In Astro: import GatedDownload from '../components/innovations/freebies/gated-download'; <GatedDownload client:visible /> In Next.js: import GatedDownload from '@/components/innovations/freebies/gated-download'; On form submit: 1. Send the email to your email provider (ConvertKit, Mailchimp, etc.) 2. Update the download button href to the actual file URL (can be a signed S3 URL, a Blob, or a public path) Customize: the resource title, description, and "What's inside" bullet list.