CTA Section
Dark call-to-action panel with grid texture and a breathing glow.
Ready to build something great?
Join thousands of teams shipping faster with a design system that feels alive.
components/ui/cta-section.tsx
"use client";
import { motion } from "motion/react";
import { ArrowRight } from "lucide-react";
type CtaSectionProps = {
title?: string;
description?: string;
primary?: string;
secondary?: string;
};
export function CtaSection({
title = "Ready to build something great?",
description = "Join thousands of teams shipping faster with a design system that feels alive.",
primary = "Start building",
secondary = "Talk to sales",
}: CtaSectionProps) {
return (
<motion.section
initial={{ opacity: 0, y: 30, scale: 0.98 }}
whileInView={{ opacity: 1, y: 0, scale: 1 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.8, ease: [0.22, 1, 0.36, 1] }}
className="relative isolate overflow-hidden rounded-[2rem] bg-zinc-950 px-6 py-20 text-center sm:px-16"
>
<div
aria-hidden
className="absolute inset-0 -z-10 opacity-40 [background-image:linear-gradient(to_right,rgba(255,255,255,0.08)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.08)_1px,transparent_1px)] [background-size:44px_44px] [mask-image:radial-gradient(ellipse_at_center,black_30%,transparent_75%)]"
/>
<motion.div
aria-hidden
className="absolute left-1/2 top-0 -z-10 h-72 w-[36rem] -translate-x-1/2 -translate-y-1/2 rounded-full bg-blue-600/40 blur-3xl"
animate={{ opacity: [0.5, 0.9, 0.5], scale: [1, 1.1, 1] }}
transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }}
/>
<h2 className="mx-auto max-w-2xl text-balance text-4xl font-semibold tracking-tight text-white sm:text-5xl">{title}</h2>
<p className="mx-auto mt-5 max-w-xl text-lg text-zinc-400">{description}</p>
<div className="mt-10 flex flex-wrap items-center justify-center gap-3">
<button className="group inline-flex items-center gap-2 rounded-full bg-white px-6 py-3 text-sm font-medium text-zinc-900 transition hover:-translate-y-0.5">
{primary}
<ArrowRight className="size-4 transition-transform group-hover:translate-x-0.5" />
</button>
<button className="rounded-full px-6 py-3 text-sm font-medium text-white ring-1 ring-white/20 transition hover:bg-white/10">
{secondary}
</button>
</div>
</motion.section>
);
}
export default function Demo() {
return (
<div className="w-full max-w-5xl">
<CtaSection />
</div>
);
}
Installation
Install the dependencies
$ npm i motion lucide-reactCopy the source into
components/ui/cta-section.tsxcomponents/ui/cta-section.tsx"use client"; import { motion } from "motion/react"; import { ArrowRight } from "lucide-react"; type CtaSectionProps = { title?: string; description?: string; primary?: string; secondary?: string; }; export function CtaSection({ title = "Ready to build something great?", description = "Join thousands of teams shipping faster with a design system that feels alive.", primary = "Start building", secondary = "Talk to sales", }: CtaSectionProps) { return ( <motion.section initial={{ opacity: 0, y: 30, scale: 0.98 }} whileInView={{ opacity: 1, y: 0, scale: 1 }} viewport={{ once: true, amount: 0.4 }} transition={{ duration: 0.8, ease: [0.22, 1, 0.36, 1] }} className="relative isolate overflow-hidden rounded-[2rem] bg-zinc-950 px-6 py-20 text-center sm:px-16" > <div aria-hidden className="absolute inset-0 -z-10 opacity-40 [background-image:linear-gradient(to_right,rgba(255,255,255,0.08)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.08)_1px,transparent_1px)] [background-size:44px_44px] [mask-image:radial-gradient(ellipse_at_center,black_30%,transparent_75%)]" /> <motion.div aria-hidden className="absolute left-1/2 top-0 -z-10 h-72 w-[36rem] -translate-x-1/2 -translate-y-1/2 rounded-full bg-blue-600/40 blur-3xl" animate={{ opacity: [0.5, 0.9, 0.5], scale: [1, 1.1, 1] }} transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }} /> <h2 className="mx-auto max-w-2xl text-balance text-4xl font-semibold tracking-tight text-white sm:text-5xl">{title}</h2> <p className="mx-auto mt-5 max-w-xl text-lg text-zinc-400">{description}</p> <div className="mt-10 flex flex-wrap items-center justify-center gap-3"> <button className="group inline-flex items-center gap-2 rounded-full bg-white px-6 py-3 text-sm font-medium text-zinc-900 transition hover:-translate-y-0.5"> {primary} <ArrowRight className="size-4 transition-transform group-hover:translate-x-0.5" /> </button> <button className="rounded-full px-6 py-3 text-sm font-medium text-white ring-1 ring-white/20 transition hover:bg-white/10"> {secondary} </button> </div> </motion.section> ); } export default function Demo() { return ( <div className="w-full max-w-5xl"> <CtaSection /> </div> ); }Use it
The file exports the component and a
Demoshowing typical usage. Import whichever you need.