Form Capture Hero
Original · freehero with an inline signup form
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/herox-form-capture.json"use client";
import { useId, useState, type FormEvent } from "react";
import { motion, useReducedMotion } from "motion/react";
type Status = "idle" | "loading" | "success" | "error";
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const BARS: readonly number[] = [42, 61, 47, 73, 55, 88, 69];
export default function HeroxFormCapture() {
const reduce = useReducedMotion();
const emailId = useId();
const hintId = useId();
const [email, setEmail] = useState("");
const [status, setStatus] = useState<Status>("idle");
function handleSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
if (!EMAIL_RE.test(email.trim())) {
setStatus("error");
return;
}
setStatus("loading");
window.setTimeout(() => setStatus("success"), 900);
}
function resetForm() {
setStatus("idle");
setEmail("");
}
const rise = (delay: number) => ({
initial: reduce ? { opacity: 0 } : { opacity: 0, y: 24 },
whileInView: reduce ? { opacity: 1 } : { opacity: 1, y: 0 },
viewport: { once: true, margin: "-80px" as const },
transition: { duration: 0.6, delay, ease: "easeOut" as const },
});
return (
<section className="relative w-full overflow-hidden bg-white py-24 text-slate-900 sm:py-32 dark:bg-slate-950 dark:text-slate-100">
<style>{`
@keyframes hxfc-float {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-14px) rotate(-1.5deg); }
}
@keyframes hxfc-drift {
0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
50% { transform: translate3d(18px, -22px, 0) scale(1.06); }
}
@keyframes hxfc-grow {
from { transform: scaleY(0.15); opacity: 0.4; }
to { transform: scaleY(1); opacity: 1; }
}
@keyframes hxfc-pulse {
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.55); }
70% { box-shadow: 0 0 0 9px rgba(16, 185, 129, 0); }
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
@keyframes hxfc-spin {
to { transform: rotate(360deg); }
}
@keyframes hxfc-dash {
from { stroke-dashoffset: 320; }
to { stroke-dashoffset: 0; }
}
.hxfc-blob-a { animation: hxfc-drift 16s ease-in-out infinite; }
.hxfc-blob-b { animation: hxfc-drift 20s ease-in-out infinite reverse; }
.hxfc-badge-a { animation: hxfc-float 7s ease-in-out infinite; }
.hxfc-badge-b { animation: hxfc-float 9s ease-in-out infinite 0.8s; }
.hxfc-bar { transform-origin: bottom; animation: hxfc-grow 0.9s cubic-bezier(0.16, 1, 0.3, 1) both; }
.hxfc-dot { animation: hxfc-pulse 2s ease-out infinite; }
.hxfc-spin { animation: hxfc-spin 0.7s linear infinite; }
.hxfc-line { stroke-dasharray: 320; animation: hxfc-dash 1.6s ease-out 0.3s both; }
@media (prefers-reduced-motion: reduce) {
.hxfc-blob-a, .hxfc-blob-b, .hxfc-badge-a, .hxfc-badge-b,
.hxfc-bar, .hxfc-dot, .hxfc-spin, .hxfc-line {
animation: none !important;
}
.hxfc-line { stroke-dashoffset: 0; }
}
`}</style>
{/* Decorative background */}
<div aria-hidden className="pointer-events-none absolute inset-0 overflow-hidden">
<div className="hxfc-blob-a absolute -left-24 -top-24 h-96 w-96 rounded-full bg-gradient-to-br from-indigo-300/50 to-violet-300/40 blur-3xl dark:from-indigo-600/30 dark:to-violet-600/20" />
<div className="hxfc-blob-b absolute -right-28 top-40 h-[26rem] w-[26rem] rounded-full bg-gradient-to-tr from-sky-300/40 to-emerald-300/30 blur-3xl dark:from-sky-600/25 dark:to-emerald-600/15" />
<svg className="absolute inset-0 h-full w-full text-slate-900/[0.04] dark:text-white/[0.05]" aria-hidden>
<defs>
<pattern id="hxfc-grid" width="44" height="44" patternUnits="userSpaceOnUse">
<path d="M44 0H0V44" fill="none" stroke="currentColor" strokeWidth="1" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#hxfc-grid)" />
</svg>
</div>
<div className="relative mx-auto grid max-w-6xl grid-cols-1 items-center gap-16 px-6 lg:grid-cols-2 lg:gap-10">
{/* Left: copy + form */}
<div className="max-w-xl">
<motion.span
{...rise(0)}
className="inline-flex items-center gap-2 rounded-full border border-indigo-200 bg-indigo-50 px-3 py-1 text-xs font-medium text-indigo-700 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-300"
>
<span className="hxfc-dot h-1.5 w-1.5 rounded-full bg-emerald-500" />
New: instant event pipelines
</motion.span>
<motion.h1
{...rise(0.08)}
className="mt-6 text-4xl font-semibold tracking-tight text-slate-900 sm:text-5xl lg:text-[3.4rem] lg:leading-[1.05] dark:text-white"
>
Turn raw product events into decisions your team actually{" "}
<span className="bg-gradient-to-r from-indigo-600 via-violet-600 to-sky-600 bg-clip-text text-transparent dark:from-indigo-400 dark:via-violet-400 dark:to-sky-400">
ships this week.
</span>
</motion.h1>
<motion.p
{...rise(0.16)}
className="mt-6 text-lg leading-relaxed text-slate-600 dark:text-slate-400"
>
Cadence unifies product, marketing, and revenue data in one workspace, so
teams stop arguing about numbers and start acting on them. Your first live
dashboard takes under ten minutes, no data engineer required.
</motion.p>
<motion.div {...rise(0.24)}>
{status === "success" ? (
<div
role="status"
className="mt-8 flex w-full max-w-md items-start gap-3 rounded-2xl border border-emerald-200 bg-emerald-50 p-5 dark:border-emerald-500/30 dark:bg-emerald-500/10"
>
<span className="mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-emerald-500 text-white">
<svg viewBox="0 0 20 20" className="h-4 w-4" fill="none" aria-hidden>
<path d="M4 10.5l4 4 8-9" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
<div>
<p className="text-sm font-semibold text-emerald-900 dark:text-emerald-200">
You're on the list.
</p>
<p className="mt-1 text-sm text-emerald-800/80 dark:text-emerald-300/80">
We sent a setup link to <span className="font-medium">{email.trim()}</span>. Check your inbox to spin up your workspace.
</p>
<button
type="button"
onClick={resetForm}
className="mt-3 rounded-md text-sm font-medium text-emerald-700 underline underline-offset-4 hover:text-emerald-900 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-50 dark:text-emerald-300 dark:hover:text-emerald-200 dark:focus-visible:ring-offset-slate-950"
>
Use a different email
</button>
</div>
</div>
) : (
<form onSubmit={handleSubmit} noValidate className="mt-8 w-full max-w-md">
<div className="flex flex-col gap-3 sm:flex-row">
<div className="relative flex-1">
<label htmlFor={emailId} className="sr-only">
Work email address
</label>
<span className="pointer-events-none absolute inset-y-0 left-3.5 flex items-center text-slate-400 dark:text-slate-500">
<svg viewBox="0 0 24 24" className="h-5 w-5" fill="none" aria-hidden>
<rect x="3" y="5" width="18" height="14" rx="2.5" stroke="currentColor" strokeWidth="1.6" />
<path d="M4 7l8 6 8-6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
<input
id={emailId}
name="email"
type="email"
inputMode="email"
autoComplete="email"
placeholder="you@company.com"
value={email}
onChange={(e) => {
setEmail(e.target.value);
if (status === "error") setStatus("idle");
}}
aria-invalid={status === "error"}
aria-describedby={hintId}
disabled={status === "loading"}
className={`w-full rounded-xl border bg-white py-3.5 pl-11 pr-4 text-sm text-slate-900 shadow-sm outline-none transition placeholder:text-slate-400 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:opacity-60 dark:bg-slate-900 dark:text-white dark:placeholder:text-slate-500 dark:focus-visible:ring-offset-slate-950 ${
status === "error"
? "border-rose-400 focus-visible:ring-rose-500 dark:border-rose-500/60"
: "border-slate-300 focus-visible:ring-indigo-500 dark:border-slate-700"
}`}
/>
</div>
<button
type="submit"
disabled={status === "loading"}
className="inline-flex shrink-0 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-6 py-3.5 text-sm font-semibold text-white shadow-sm transition hover:bg-indigo-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-70 dark:focus-visible:ring-offset-slate-950"
>
{status === "loading" ? (
<>
<svg viewBox="0 0 24 24" className="hxfc-spin h-4 w-4" fill="none" aria-hidden>
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeOpacity="0.3" strokeWidth="3" />
<path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />
</svg>
<span>Setting up</span>
</>
) : (
<>
<span>Start free</span>
<svg viewBox="0 0 20 20" className="h-4 w-4" fill="none" aria-hidden>
<path d="M4 10h11m0 0l-4-4m4 4l-4 4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</>
)}
</button>
</div>
<p
id={hintId}
aria-live="polite"
className={`mt-3 text-sm ${
status === "error"
? "text-rose-600 dark:text-rose-400"
: "text-slate-500 dark:text-slate-500"
}`}
>
{status === "error"
? "Please enter a valid work email address."
: "Free 14-day trial. No credit card required. Cancel anytime."}
</p>
</form>
)}
</motion.div>
{/* Trust row */}
<motion.div
{...rise(0.32)}
className="mt-9 flex flex-wrap items-center gap-x-6 gap-y-4"
>
<div className="flex items-center">
<div className="flex -space-x-2.5">
{[
{ i: "AR", c: "from-indigo-500 to-violet-500" },
{ i: "MK", c: "from-sky-500 to-cyan-500" },
{ i: "JP", c: "from-emerald-500 to-teal-500" },
{ i: "LS", c: "from-amber-500 to-rose-500" },
].map((a) => (
<span
key={a.i}
className={`flex h-9 w-9 items-center justify-center rounded-full bg-gradient-to-br ${a.c} text-[0.65rem] font-bold text-white ring-2 ring-white dark:ring-slate-950`}
>
{a.i}
</span>
))}
</div>
<p className="ml-3 text-sm text-slate-600 dark:text-slate-400">
Join <span className="font-semibold text-slate-900 dark:text-white">6,200+</span> product teams
</p>
</div>
<div className="flex items-center gap-2">
<div className="flex" aria-hidden>
{Array.from({ length: 5 }).map((_, i) => (
<svg key={i} viewBox="0 0 20 20" className="h-4 w-4 text-amber-400" fill="currentColor">
<path d="M10 1.6l2.47 5.01 5.53.8-4 3.9.94 5.5L10 14.2l-4.94 2.6.94-5.5-4-3.9 5.53-.8z" />
</svg>
))}
</div>
<span className="text-sm text-slate-600 dark:text-slate-400">
<span className="font-semibold text-slate-900 dark:text-white">4.9</span>/5 average rating
</span>
</div>
</motion.div>
</div>
{/* Right: dashboard visual */}
<motion.div
initial={reduce ? { opacity: 0 } : { opacity: 0, scale: 0.94, y: 20 }}
whileInView={reduce ? { opacity: 1 } : { opacity: 1, scale: 1, y: 0 }}
viewport={{ once: true, margin: "-80px" }}
transition={{ duration: 0.7, delay: 0.2, ease: "easeOut" }}
className="relative mx-auto w-full max-w-md lg:mx-0"
>
{/* Floating badge: live */}
<div className="hxfc-badge-a absolute -left-4 top-10 z-20 flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2 shadow-lg shadow-slate-900/5 dark:border-slate-700 dark:bg-slate-900">
<span className="hxfc-dot h-2 w-2 rounded-full bg-emerald-500" />
<span className="text-xs font-medium text-slate-700 dark:text-slate-200">Streaming live</span>
</div>
{/* Floating badge: signups */}
<div className="hxfc-badge-b absolute -right-3 bottom-12 z-20 rounded-xl border border-slate-200 bg-white px-3.5 py-2.5 shadow-lg shadow-slate-900/5 dark:border-slate-700 dark:bg-slate-900">
<p className="text-[0.65rem] font-medium uppercase tracking-wide text-slate-400 dark:text-slate-500">
Signups today
</p>
<p className="text-lg font-bold text-slate-900 dark:text-white">+318</p>
</div>
{/* Main card */}
<div className="relative rounded-3xl border border-slate-200 bg-white/90 p-6 shadow-2xl shadow-indigo-900/10 backdrop-blur-sm dark:border-slate-800 dark:bg-slate-900/90">
<div className="flex items-start justify-between">
<div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400">Weekly active users</p>
<p className="mt-1 text-3xl font-bold tracking-tight text-slate-900 dark:text-white">48,204</p>
</div>
<span className="inline-flex items-center gap-1 rounded-full bg-emerald-100 px-2.5 py-1 text-xs font-semibold text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-400">
<svg viewBox="0 0 16 16" className="h-3 w-3" fill="none" aria-hidden>
<path d="M3 11l4-4 3 3 4-5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
12.4%
</span>
</div>
{/* Bars */}
<div className="mt-6 flex h-36 items-end justify-between gap-2.5">
{BARS.map((h, i) => {
const active = i === BARS.length - 2;
return (
<div key={i} className="flex h-full flex-1 items-end">
<div
className={`hxfc-bar w-full rounded-t-md ${
active
? "bg-gradient-to-t from-indigo-600 to-violet-500"
: "bg-slate-200 dark:bg-slate-700"
}`}
style={{ height: `${h}%`, animationDelay: `${0.15 + i * 0.08}s` }}
/>
</div>
);
})}
</div>
{/* Sparkline row */}
<div className="mt-6 rounded-2xl border border-slate-100 bg-slate-50 p-4 dark:border-slate-800 dark:bg-slate-800/40">
<div className="flex items-center justify-between">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400">Conversion trend</p>
<p className="text-xs font-semibold text-slate-700 dark:text-slate-200">7.8%</p>
</div>
<svg viewBox="0 0 320 64" className="mt-2 h-14 w-full" fill="none" aria-hidden preserveAspectRatio="none">
<defs>
<linearGradient id="hxfc-spark" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="rgb(99,102,241)" stopOpacity="0.28" />
<stop offset="100%" stopColor="rgb(99,102,241)" stopOpacity="0" />
</linearGradient>
</defs>
<path d="M0 46 L46 40 L92 48 L138 30 L184 34 L230 18 L276 24 L320 8 L320 64 L0 64 Z" fill="url(#hxfc-spark)" />
<path
className="hxfc-line"
d="M0 46 L46 40 L92 48 L138 30 L184 34 L230 18 L276 24 L320 8"
stroke="rgb(99,102,241)"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
</div>
</motion.div>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Spotlight Hero
OriginalA centred hero with a soft radial spotlight, badge and dual call-to-action.

Split Hero
OriginalA two-column hero pairing a headline and CTAs with a product mock and social proof.

Gradient Spotlight Hero
OriginalA minimal centred hero with a soft gradient-mesh backdrop, announcement pill and dual call-to-action buttons.

App Preview Hero
OriginalA centred hero that pairs headline copy with a realistic product dashboard mock built entirely from markup, complete with browser chrome and a floating notification card.

Waitlist Capture Hero
OriginalA dark, focused hero with an inline email capture form and avatar social proof, ready for pre-launch waitlists.

Image Backdrop Hero
OriginalA cinematic full-bleed hero with a layered image-style backdrop, overlaid left-aligned copy and a trusted-by logos strip.

Gradient Mesh Hero with Staggered Text Reveal
OriginalA full-screen hero pairing a drifting animated gradient-mesh backdrop with a word-by-word staggered blur-in headline and a logo marquee under the fold.

Typewriter Rotating Words Hero
OriginalA hero whose headline cycles through rotating words with a live typewriter caret over an animated grid backdrop, degrading to a gentle word swap when reduced motion is on.

Floating UI Cards Hero with Mouse Parallax
OriginalA hero with glassy floating UI cards that drift continuously and shift on mouse-parallax depth around a staggered centre headline.

Aurora Hero with Shimmer CTA and Logo Marquee
OriginalA dark hero with animated aurora light beams, a shimmering sweep across the primary CTA, and dual-direction logo marquees beneath the fold.

Gradient Conversion Hero
MITCentered, full-screen marketing hero with a colour-accent headline word, supporting copy, and dual primary/secondary CTA buttons. Dark-mode ready and dependency-free.

Split Showcase Hero
MITTwo-column hero on a dark background with a headline, paragraph, and two buttons beside a gradient media panel. Responsive column stack on mobile.

