← CTAOpen in v0
CTA 02 — Newsletter Band
Full-bleed newsletter band with grid texture, corner gradient and an email capture form with privacy note.
$ npx shadcn@latest add @ludusvibe/cta-02Code
Installed to components/sections/cta-02.tsx — it's yours to edit.
"use client"
import * as React from "react"
import { buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Reveal } from "@/components/ludus/reveal"
import { cn } from "@/lib/utils"
export type Cta02Props = {
eyebrow?: string
title?: React.ReactNode
description?: string
/** Accessible label for the email field. */
inputLabel?: string
placeholder?: string
buttonLabel?: string
privacyNote?: React.ReactNode
/** Handle the submit yourself (e.g. call your API). Defaults to a plain `action="#"` form. */
onSubmit?: React.FormEventHandler<HTMLFormElement>
/** Heading element — use "h1" when this is the page's main heading. */
as?: "h1" | "h2"
className?: string
}
export function Cta02({
eyebrow = "Newsletter",
title = "Stay ahead of every release",
description = "One email a month with product updates, practical playbooks and early access to new features. Written by the team, readable in three minutes.",
inputLabel = "Email address",
placeholder = "you@company.com",
buttonLabel = "Subscribe",
privacyNote = "No spam, ever. Unsubscribe with one click.",
onSubmit,
as: Heading = "h2",
className,
}: Cta02Props) {
return (
<section
className={cn("relative overflow-hidden border-y bg-background", className)}
>
<div
aria-hidden
className="absolute inset-0 [background-image:linear-gradient(to_right,var(--border)_1px,transparent_1px),linear-gradient(to_bottom,var(--border)_1px,transparent_1px)] [background-size:32px_32px] [mask-image:radial-gradient(ellipse_80%_120%_at_100%_0%,black,transparent)]"
/>
<div
aria-hidden
className="absolute inset-0 bg-gradient-to-bl from-primary/10 via-transparent to-transparent"
/>
<div className="relative mx-auto grid max-w-6xl items-center gap-10 px-6 py-20 md:py-24 lg:grid-cols-[1fr_auto] lg:gap-16">
<div className="text-center lg:text-left">
<Reveal>
<p className="text-sm font-medium tracking-widest text-primary uppercase">
{eyebrow}
</p>
</Reveal>
<Reveal delay={0.1}>
<Heading className="mt-3 text-balance font-heading text-3xl font-semibold tracking-tight md:text-4xl">
{title}
</Heading>
</Reveal>
<Reveal delay={0.2}>
<p className="mx-auto mt-4 max-w-xl text-pretty text-muted-foreground md:text-lg lg:mx-0">
{description}
</p>
</Reveal>
</div>
<Reveal delay={0.3} className="w-full lg:w-auto">
<form
action="#"
onSubmit={onSubmit}
className="mx-auto flex w-full max-w-md flex-col gap-3 sm:flex-row"
>
<Input
type="email"
name="email"
required
autoComplete="email"
aria-label={inputLabel}
placeholder={placeholder}
className="h-9 flex-1 bg-background sm:min-w-64"
/>
<button type="submit" className={buttonVariants({ size: "lg" })}>
{buttonLabel}
</button>
</form>
<p className="mt-3 text-center text-xs text-muted-foreground lg:text-left">
{privacyNote}
</p>
</Reveal>
</div>
</section>
)
}