Everything you need to build amazing products
Powerful features and tools designed for modern development teams. Built to scale with your business.
Developer Tools
Built-in DevTools offer insights, transparency, and easy management of your app's performance.
Beautiful Design
Create stunning interfaces with our comprehensive design system and component library.
Lightning Fast
Optimized performance with edge computing and global CDN distribution.
Global Infrastructure
Deploy to 150+ edge locations worldwide for optimal performance everywhere.
Enterprise Security
Bank-level encryption, SOC 2 compliance, and advanced security features.
Analytics Dashboard
Real-time insights with customizable dashboards and detailed reporting.
Features
- ✅ Premium Animations - Staggered entrance and smooth hover effects using Framer Motion
- ✅ Glassmorphism - Modern frosted glass look with backdrop blur
- ✅ Asymmetric Layout - Flexible bento grid design
- ✅ Interactive Cards - Hover lifts, glows, and deep shadows
- ✅ Rich Content - Support for icons, custom visuals, and call-to-action links
- ✅ Flexible Sizing - Span columns, rows, or both
- ✅ Responsive - Adapts seamlessly from mobile to desktop
- ✅ TypeScript Support - Full type safety
- ✅ Customizable - Easy to style and extend via className
Installation
Install dependencies
npm install framer-motion lucide-reactCopy and paste the following code into your project.
import { motion } from "framer-motion";
import { LucideIcon } from "lucide-react";
import { ReactNode } from "react";
import { cn } from "@/lib/utils";
interface BentoFeature {
title: string;
description: string;
icon?: LucideIcon;
span?: "col" | "row" | "both";
visual?: ReactNode;
className?: string;
cta?: string;
href?: string;
}
interface FeatureBentoGridProps {
headline: string;
description?: string;
features: BentoFeature[];
className?: string;
}
const BentoCard = ({
feature,
className,
}: {
feature: BentoFeature;
className?: string;
}) => {
const Icon = feature.icon;
const getSpanClass = (span?: "col" | "row" | "both") => {
switch (span) {
case "col":
return "md:col-span-2";
case "row":
return "md:row-span-2";
case "both":
return "md:col-span-2 md:row-span-2";
default:
return "";
}
};
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-50px" }}
transition={{ duration: 0.5, ease: "easeOut" }}
className={cn(
"group relative flex flex-col overflow-hidden rounded-3xl border border-zinc-800 bg-zinc-900/50 p-6 backdrop-blur-sm transition-all duration-300 hover:border-zinc-700/50 hover:bg-zinc-900/80 hover:shadow-2xl hover:shadow-zinc-900/20",
getSpanClass(feature.span),
className,
)}
>
{/* Gradient Glow Effect */}
<div className="absolute -right-20 -top-20 h-64 w-64 rounded-full bg-zinc-800/20 blur-3xl transition-all duration-500 group-hover:bg-zinc-700/30" />
<div className="absolute -bottom-20 -left-20 h-64 w-64 rounded-full bg-zinc-800/20 blur-3xl transition-all duration-500 group-hover:bg-zinc-700/30" />
<div className="relative z-10 flex h-full flex-col justify-between gap-6">
<div className="flex flex-col gap-4">
{Icon && (
<div className="flex h-12 w-12 items-center justify-center rounded-xl border border-zinc-800 bg-zinc-900/80 shadow-inner">
<Icon className="h-6 w-6 text-zinc-100" />
</div>
)}
<div>
<h3 className="text-xl font-semibold tracking-tight text-zinc-100">
{feature.title}
</h3>
<p className="mt-2 text-base leading-relaxed text-zinc-400">
{feature.description}
</p>
</div>
</div>
{feature.visual && (
<div className="relative mt-auto overflow-hidden rounded-xl border border-zinc-800/50 bg-zinc-950/50">
{feature.visual}
</div>
)}
{feature.cta && (
<div className="mt-4 flex items-center gap-2 text-sm font-medium text-zinc-300 transition-colors group-hover:text-white">
{feature.cta}
<svg
className="h-4 w-4 transition-transform duration-300 group-hover:translate-x-1"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M17 8l4 4m0 0l-4 4m4-4H3"
/>
</svg>
</div>
)}
</div>
</motion.div>
);
};
export function FeatureBentoGrid({
headline,
description,
features,
className,
}: FeatureBentoGridProps) {
return (
<section
className={cn(
"relative w-full overflow-hidden bg-black py-24 sm:py-32",
className,
)}
>
{/* Background Pattern */}
<div className="absolute inset-0 z-0 opacity-30">
<div className="absolute inset-0 bg-[radial-gradient(#333_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]" />
</div>
<div className="container relative z-10 mx-auto px-4 md:px-6">
<div className="mx-auto max-w-3xl space-y-6 text-center">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="text-4xl font-bold tracking-tighter text-white sm:text-5xl md:text-6xl lg:text-7xl"
>
{headline}
</motion.h2>
{description && (
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="mx-auto max-w-2xl text-lg text-zinc-400 md:text-xl"
>
{description}
</motion.p>
)}
</div>
<div className="mx-auto mt-16 grid max-w-7xl grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{features.map((feature, index) => (
<BentoCard key={index} feature={feature} />
))}
</div>
</div>
</section>
);
}Usage
Basic Usage
import FeatureBentoGrid from "@/components/ui/feature-bento-grid";
import { Zap, Shield, Users } from "lucide-react";
export default function Page() {
return (
<FeatureBentoGrid
headline="Powerful Features"
description="Everything you need in one place."
features={[
{
title: "Lightning Fast",
description: "Blazing fast performance with edge computing.",
icon: Zap,
cta: "Learn more",
href: "/speed",
},
{
title: "Secure",
description: "Enterprise-grade security and compliance.",
icon: Shield,
cta: "Security details",
href: "/security",
},
{
title: "Collaborative",
description: "Work together seamlessly in real-time.",
icon: Users,
},
]}
/>
);
}With Spanning and Visuals
import { motion } from "framer-motion";
<FeatureBentoGrid
headline="Visual Features"
features={[
{
title: "Dashboard",
description: "Beautiful analytics dashboard.",
icon: BarChart,
span: "col",
visual: (
<div className="flex h-24 items-end gap-2 p-4">
{[40, 70, 45, 80, 55, 90].map((height, i) => (
<motion.div
key={i}
initial={{ height: 0 }}
whileInView={{ height: `${height}%` }}
transition={{ duration: 0.5, delay: i * 0.1 }}
className="w-full rounded-t bg-blue-500"
/>
))}
</div>
),
},
{
title: "Security",
description: "Enterprise-grade protection.",
icon: Shield,
span: "row",
visual: (
<div className="flex items-center justify-center py-8">
<div className="relative flex h-24 w-24 items-center justify-center rounded-full border-4 border-green-500/20 bg-green-500/10">
<Shield className="h-12 w-12 text-green-500" />
</div>
</div>
),
},
]}
/>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
headline | string | Required | Section headline |
description | string | undefined | Optional description |
features | BentoFeature[] | Required | Array of features |
className | string | undefined | Optional class name for the section |
TypeScript Interface
interface FeatureBentoGridProps {
headline: string;
description?: string;
features: BentoFeature[];
className?: string;
}
interface BentoFeature {
title: string;
description: string;
icon?: LucideIcon;
span?: "col" | "row" | "both";
visual?: ReactNode;
className?: string;
cta?: string;
href?: string;
}Span Options
Control how features span across the grid:
span: "col"- Spans 2 columns (wider)span: "row"- Spans 2 rows (taller)span: "both"- Spans 2 columns and 2 rows (large)- No span - Normal 1x1 size
Grid Behavior
- Mobile: Single column layout
- Tablet (md): 2 columns
- Desktop (lg): 3 columns
Spanning only applies on medium screens and above.
Use Cases
Perfect for:
- SaaS Feature sections
- Product capability showcases
- Interactive portfolio galleries
- Service offerings with rich visuals
- Modern landing pages