Hero
Landing hero with animated headline, glowing background and call-to-action buttons.
l8components 1.0 is here
Buildbeautifulproducts,faster.
One design system for every product team. Accessible components, ready-made blocks and motion that feels right, all built on shadcn/ui.
Installation
npx shadcn@latest add @l8/heroUsage
import { HeroBlock } from '@/components/blocks/hero';
export default function Page() {
return <HeroBlock />;
}Source
"use client"
import Link from "next/link"
import { motion } from "motion/react"
import { ArrowRightIcon, SparklesIcon } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { buttonVariants } from "@/components/ui/button"
const words = ["Build", "beautiful", "products,", "faster."]
export function HeroBlock() {
return (
<section className="@container relative isolate overflow-hidden px-6 py-20 @2xl:py-28">
<Glow />
<div className="mx-auto flex max-w-3xl flex-col items-center text-center">
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5 }}
>
<Badge variant="outline" className="gap-1.5 rounded-full bg-background/60 px-3 py-1 backdrop-blur">
<SparklesIcon className="text-primary" />
l8components 1.0 is here
</Badge>
</motion.div>
<h1 className="mt-6 text-4xl font-semibold tracking-tight text-balance @2xl:text-6xl">
{words.map((word, i) => (
<motion.span
key={word}
className="inline-block pr-[0.25em]"
initial={{ opacity: 0, y: 24, filter: "blur(8px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
transition={{ duration: 0.6, delay: 0.15 + i * 0.1, ease: [0.22, 1, 0.36, 1] }}
>
{i === 1 ? (
<span className="text-primary">
{word}
</span>
) : (
word
)}
</motion.span>
))}
</h1>
<motion.p
className="mt-5 max-w-xl text-base text-muted-foreground @2xl:text-lg"
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.6 }}
>
One design system for every product team. Accessible components, ready-made
blocks and motion that feels right, all built on shadcn/ui.
</motion.p>
<motion.div
className="mt-8 flex flex-wrap justify-center gap-3"
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.75 }}
>
<Link href="/docs/components/button" className={buttonVariants({ size: "lg", className: "rounded-full px-5" })}>
Browse components
<ArrowRightIcon data-icon="inline-end" />
</Link>
<Link
href="/docs/blocks/hero"
className={buttonVariants({ size: "lg", variant: "outline", className: "rounded-full px-5" })}
>
Explore blocks
</Link>
</motion.div>
</div>
</section>
)
}
function Glow() {
return (
<div aria-hidden className="pointer-events-none absolute inset-0 -z-10">
<motion.div
className="absolute top-[-20%] left-1/2 size-[36rem] -translate-x-1/2 rounded-full bg-primary/10 blur-3xl"
animate={{ scale: [1, 1.15, 1], opacity: [0.6, 1, 0.6] }}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
className="absolute top-1/3 left-[10%] size-72 rounded-full bg-primary/5 blur-3xl"
animate={{ x: [0, 40, 0], y: [0, -20, 0] }}
transition={{ duration: 10, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
className="absolute top-1/2 right-[10%] size-64 rounded-full bg-foreground/5 blur-3xl"
animate={{ x: [0, -30, 0], y: [0, 30, 0] }}
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut" }}
/>
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,var(--border)_1px,transparent_1px)] mask-[radial-gradient(ellipse_at_center,black,transparent_70%)] bg-size-[24px_24px]" />
</div>
)
}