Scroll-reveal bento grid
Original · freeAn asymmetric bento feature grid whose cards stagger into view on scroll, lift on hover and feature an animated conic gradient border, shimmering headline, growing bar chart and a masked marquee tag strip.
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/afeature-scroll-reveal-bento.json"use client";
import type { ReactNode } from "react";
import { motion } from "motion/react";
const gridReveal = {
hidden: {},
show: { transition: { staggerChildren: 0.09, delayChildren: 0.05 } },
};
const cellReveal = {
hidden: { opacity: 0, y: 32, scale: 0.97 },
show: {
opacity: 1,
y: 0,
scale: 1,
transition: { type: "spring", stiffness: 130, damping: 20 },
},
};
function IconBolt() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
<path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z" />
</svg>
);
}
function IconChart() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
<path d="M4 20V10M10 20V4M16 20v-6M22 20H2" />
</svg>
);
}
function IconShield() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
<path d="M12 3 5 6v6c0 4 3 6.5 7 9 4-2.5 7-5 7-9V6l-7-3Z" />
<path d="m9 12 2 2 4-4" />
</svg>
);
}
function IconGlobe() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
<circle cx="12" cy="12" r="9" />
<path d="M3 12h18M12 3c2.5 2.5 3.5 6 3.5 9S14.5 18.5 12 21c-2.5-2.5-3.5-6-3.5-9S9.5 5.5 12 3Z" />
</svg>
);
}
function IconLayers() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" className="h-5 w-5" aria-hidden="true">
<path d="m12 3 9 5-9 5-9-5 9-5Z" />
<path d="m3 13 9 5 9-5M3 17l9 5 9-5" />
</svg>
);
}
const tags = ["Real-time sync", "Edge caching", "Role-based access", "Audit trails", "Webhooks", "Custom fields", "SSO ready", "API-first"];
function Card({ className = "", children }: { className?: string; children: ReactNode }) {
return (
<motion.div
variants={cellReveal}
whileHover={{ y: -6 }}
transition={{ type: "spring", stiffness: 300, damping: 22 }}
className={`group relative overflow-hidden rounded-3xl border border-slate-200/70 bg-white/70 p-6 backdrop-blur-sm dark:border-white/10 dark:bg-white/[0.04] ${className}`}
>
<div className="pointer-events-none absolute -right-16 -top-16 h-40 w-40 rounded-full bg-indigo-400/20 opacity-0 blur-3xl transition-opacity duration-500 group-hover:opacity-100 dark:bg-indigo-500/25" />
{children}
</motion.div>
);
}
export default function ScrollRevealBento() {
return (
<section className="relative w-full overflow-hidden bg-slate-50 px-5 py-24 text-slate-900 dark:bg-slate-950 dark:text-white sm:px-8">
<style>{`
@keyframes afb-spin { to { transform: rotate(360deg); } }
@keyframes afb-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@keyframes afb-float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes afb-marquee { to { transform: translateX(-50%); } }
.afb-spin { animation: afb-spin 7s linear infinite; }
.afb-shimmer { background-size: 200% 100%; animation: afb-shimmer 3s linear infinite; }
.afb-float { animation: afb-float 6s ease-in-out infinite; }
.afb-marquee { animation: afb-marquee 20s linear infinite; }
@media (prefers-reduced-motion: reduce) {
.afb-spin, .afb-shimmer, .afb-float, .afb-marquee { animation: none !important; }
}
`}</style>
<div className="pointer-events-none absolute left-1/2 top-0 h-72 w-[42rem] max-w-full -translate-x-1/2 rounded-full bg-indigo-300/30 blur-[100px] dark:bg-indigo-600/20" />
<motion.header
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ duration: 0.6, ease: "easeOut" }}
className="relative mx-auto max-w-2xl text-center"
>
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1 text-xs font-medium text-slate-600 dark:border-white/10 dark:bg-white/5 dark:text-slate-300">
<span className="h-1.5 w-1.5 rounded-full bg-indigo-500" />
Platform overview
</span>
<h2 className="mt-5 text-balance text-4xl font-semibold tracking-tight sm:text-5xl">
Everything your team needs, in one canvas
</h2>
<p className="mx-auto mt-4 max-w-xl text-pretty text-base text-slate-600 dark:text-slate-400">
A modular workspace that scales with you. Reveal, hover and explore the pieces that make it work.
</p>
</motion.header>
<motion.div
variants={gridReveal}
initial="hidden"
whileInView="show"
viewport={{ once: true, amount: 0.15 }}
className="relative mx-auto mt-14 grid max-w-6xl grid-cols-1 gap-4 sm:grid-cols-2 lg:auto-rows-[210px] lg:grid-cols-4"
>
{/* Hero card with animated gradient border */}
<motion.div
variants={cellReveal}
whileHover={{ y: -6 }}
transition={{ type: "spring", stiffness: 300, damping: 22 }}
className="group relative overflow-hidden rounded-3xl sm:col-span-2 lg:col-span-2 lg:row-span-2"
>
<div
className="afb-spin absolute inset-[-45%] opacity-70"
style={{ background: "conic-gradient(from 0deg, transparent 0deg, rgba(99,102,241,0.9) 55deg, rgba(217,70,239,0.7) 90deg, transparent 150deg, transparent 360deg)" }}
aria-hidden="true"
/>
<div className="relative m-[1.5px] flex h-[calc(100%-3px)] flex-col justify-between overflow-hidden rounded-[calc(1.5rem-1.5px)] bg-white p-7 dark:bg-slate-950">
<div className="pointer-events-none absolute -right-8 -top-8 h-28 w-28 afb-float rounded-full bg-gradient-to-br from-indigo-400/40 to-fuchsia-400/40 blur-2xl" />
<div>
<span className="inline-flex h-11 w-11 items-center justify-center rounded-2xl bg-indigo-500/10 text-indigo-600 dark:text-indigo-300">
<IconBolt />
</span>
<h3 className="mt-6 text-2xl font-semibold tracking-tight sm:text-3xl">
Ship features that feel{" "}
<span className="afb-shimmer bg-gradient-to-r from-slate-900 via-indigo-500 to-slate-900 bg-clip-text text-transparent dark:from-white dark:via-indigo-300 dark:to-white">
genuinely alive
</span>
</h3>
<p className="mt-3 max-w-md text-sm leading-relaxed text-slate-600 dark:text-slate-400">
Compose motion, data and layout without wrestling a build step. Every block is responsive, accessible and ready to personalise.
</p>
</div>
<dl className="mt-6 grid grid-cols-3 gap-4 border-t border-slate-200/70 pt-5 dark:border-white/10">
{[
["12x", "Faster setup"],
["40+", "Ready blocks"],
["0", "Config files"],
].map(([n, l]) => (
<div key={l}>
<dt className="text-2xl font-semibold text-slate-900 dark:text-white">{n}</dt>
<dd className="mt-0.5 text-xs text-slate-500 dark:text-slate-400">{l}</dd>
</div>
))}
</dl>
</div>
</motion.div>
{/* Wide stat card with animated bars */}
<Card className="sm:col-span-2 lg:col-span-2">
<div className="flex h-full flex-col justify-between">
<div className="flex items-start justify-between">
<div>
<span className="inline-flex h-10 w-10 items-center justify-center rounded-xl bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
<IconChart />
</span>
<p className="mt-4 text-sm font-medium text-slate-500 dark:text-slate-400">Weekly performance</p>
<p className="text-3xl font-semibold tracking-tight">99.98% uptime</p>
</div>
<span className="rounded-full bg-emerald-500/10 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:text-emerald-400">+4.2%</span>
</div>
<div className="mt-4 flex h-16 items-end gap-2">
{[40, 62, 48, 78, 56, 88, 70].map((h, i) => (
<motion.span
key={i}
initial={{ scaleY: 0 }}
whileInView={{ scaleY: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.15 + i * 0.06, type: "spring", stiffness: 140, damping: 16 }}
style={{ height: `${h}%`, transformOrigin: "bottom" }}
className="flex-1 rounded-t-md bg-gradient-to-t from-indigo-500 to-fuchsia-400"
/>
))}
</div>
</div>
</Card>
{/* Small: security */}
<Card className="lg:col-span-1">
<div className="flex h-full flex-col">
<span className="inline-flex h-10 w-10 items-center justify-center rounded-xl bg-sky-500/10 text-sky-600 dark:text-sky-400">
<IconShield />
</span>
<h3 className="mt-auto pt-4 text-base font-semibold">Secure by default</h3>
<p className="mt-1 text-sm text-slate-600 dark:text-slate-400">Encryption and access control baked in.</p>
</div>
</Card>
{/* Small: global */}
<Card className="lg:col-span-1">
<div className="flex h-full flex-col">
<span className="inline-flex h-10 w-10 items-center justify-center rounded-xl bg-violet-500/10 text-violet-600 dark:text-violet-400">
<IconGlobe />
</span>
<h3 className="mt-auto pt-4 text-base font-semibold">Global edge</h3>
<p className="mt-1 text-sm text-slate-600 dark:text-slate-400">Served from the region nearest each visitor.</p>
</div>
</Card>
{/* Wide: composable list */}
<Card className="sm:col-span-2 lg:col-span-2">
<div className="flex h-full flex-col">
<span className="inline-flex h-10 w-10 items-center justify-center rounded-xl bg-amber-500/10 text-amber-600 dark:text-amber-400">
<IconLayers />
</span>
<h3 className="mt-4 text-base font-semibold">Composable building blocks</h3>
<ul className="mt-3 grid grid-cols-2 gap-x-6 gap-y-2 text-sm text-slate-600 dark:text-slate-400">
{["Drag to arrange", "Theme-aware", "Keyboard friendly", "Zero lock-in"].map((f) => (
<li key={f} className="flex items-center gap-2">
<svg viewBox="0 0 20 20" fill="currentColor" className="h-4 w-4 shrink-0 text-indigo-500" aria-hidden="true">
<path fillRule="evenodd" d="M16.7 5.3a1 1 0 0 1 0 1.4l-7.5 7.5a1 1 0 0 1-1.4 0L3.3 10.7a1 1 0 1 1 1.4-1.4l3.1 3.1 6.8-6.8a1 1 0 0 1 1.4 0Z" clipRule="evenodd" />
</svg>
{f}
</li>
))}
</ul>
</div>
</Card>
{/* Wide: marquee tags */}
<Card className="sm:col-span-2 lg:col-span-2">
<div className="flex h-full flex-col justify-center">
<p className="text-sm font-medium text-slate-500 dark:text-slate-400">Capabilities included</p>
<div className="relative mt-3 overflow-hidden [mask-image:linear-gradient(90deg,transparent,#000_10%,#000_90%,transparent)]">
<div className="afb-marquee flex w-max gap-2">
{[...tags, ...tags].map((t, i) => (
<span key={i} className="whitespace-nowrap rounded-full border border-slate-200 bg-slate-100 px-3 py-1.5 text-xs font-medium text-slate-700 dark:border-white/10 dark:bg-white/5 dark:text-slate-300">
{t}
</span>
))}
</div>
</div>
</div>
</Card>
</motion.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 →Three Column Icon Grid
OriginalA responsive icon grid that presents six product capabilities as scannable cards, each with an inline SVG icon, title and short description.

Alternating Media Rows
OriginalThree feature rows that alternate a text column with a CSS-built visual panel, walking the reader through a plan, measure and ship story.

Bento Feature Grid
OriginalA bento-style grid mixing one large hero cell, a tall stat cell and several compact cards to give features a clear visual hierarchy.

Tabbed Feature Switcher
OriginalA tabbed feature preview that switches panels using only native radio inputs and Tailwind peer variants, so it works with no JavaScript.

Stat Backed Features
OriginalA feature layout that pairs each capability with a headline metric, so every claim is anchored to a measurable result.

Sticky scroll steps
OriginalA scroll-linked how-it-works section where a sticky panel cross-fades between steps and a progress ring plus filling timeline track advance as you scroll through the process.

Spotlight hover feature cards
OriginalA responsive feature card grid where each card follows the cursor with a radial spotlight glow, lifts and rotates its icon on hover, reveals a call to action, and sits above a scrolling logo marquee.

Animated marquee highlights band
OriginalA bold feature band with an animated gradient background, floating blurred orbs, blur-in staggered headline, two opposing marquee pill rows and shimmering stat cards.

Bordered Feature Grid (2x2)
MITA two-column grid of bordered feature cards, each pairing an outlined icon with a title and supporting copy. Clean, enterprise-leaning layout with full dark-mode support.

Outlined Feature Cards with CTA
MITA three-column feature section with heading and intro, plus blue-outlined cards that each carry an icon, description, and a circular arrow call-to-action. Fully theme-aware.

Icon-Left Feature List
MITA centered heading over a three-column feature list, each row leading with a rounded icon badge and a 'Learn More' link. Classic marketing feature block, ported with added dark variants.

Hover-Reveal Bento Grid
MITThe Magic UI bento pattern: a mixed-span grid of cards where the icon shrinks and the description lifts on hover to reveal a call-to-action. Self-contained (no framer-motion, no icon libs), pure CSS group-hover, with a glow background and full dark styling.

