Bento grids are everywhere — Apple uses them for product pages, Linear for their changelog, Vercel for their dashboard. The appeal is obvious: asymmetric card layouts create visual interest that uniform grids cannot match. Each card gets exactly the space its content needs, and the overall composition feels curated rather than templated.
This guide covers six bento grid patterns in React with Tailwind CSS, from a basic layout to animated and interactive variants. Each is copy-paste ready.
1. Basic Bento Grid
The foundation: a CSS Grid with grid-template-columns and spanning utilities. The layout uses a 4-column base grid where cards span 1 or 2 columns and rows:
export function BentoBasic() {
return (
<section className="mx-auto max-w-6xl px-4 py-24">
<h2 className="mb-12 text-center text-3xl font-bold">Why teams choose us</h2>
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
{/* Large card — 2x2 */}
<div className="col-span-2 row-span-2 rounded-2xl border border-border bg-card p-8">
<h3 className="text-2xl font-bold">Lightning fast</h3>
<p className="mt-2 text-muted-foreground">
Sub-100ms response times on every interaction.
</p>
</div>
{/* Small cards — 1x1 */}
<div className="rounded-2xl border border-border bg-card p-6">
<h3 className="font-semibold">99.9% uptime</h3>
</div>
<div className="rounded-2xl border border-border bg-card p-6">
<h3 className="font-semibold">SOC 2 certified</h3>
</div>
<div className="rounded-2xl border border-border bg-card p-6">
<h3 className="font-semibold">50+ integrations</h3>
</div>
<div className="rounded-2xl border border-border bg-card p-6">
<h3 className="font-semibold">24/7 support</h3>
</div>
</div>
</section>
);
}
The key is col-span-2 row-span-2 on the hero card. It occupies 4x the area of a regular card, creating the signature bento asymmetry.
2. Asymmetric Layout
A more editorial composition where the grid changes shape across rows. Instead of a uniform base grid, each row defines its own column split:
export function BentoAsymmetric() {
return (
<div className="mx-auto grid max-w-6xl gap-4 px-4 py-24">
{/* Row 1: 60/40 split */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-[1.5fr_1fr]">
<div className="rounded-2xl border border-border bg-card p-8">
<h3 className="text-xl font-bold">Real-time collaboration</h3>
<p className="mt-2 text-muted-foreground">
See changes as your team makes them. No refresh needed.
</p>
</div>
<div className="rounded-2xl border border-border bg-card p-8">
<h3 className="text-xl font-bold">Version history</h3>
<p className="mt-2 text-muted-foreground">Every change tracked.</p>
</div>
</div>
{/* Row 2: 40/60 split (inverted) */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-[1fr_1.5fr]">
<div className="rounded-2xl border border-border bg-card p-8">
<h3 className="text-xl font-bold">API access</h3>
<p className="mt-2 text-muted-foreground">Full REST + GraphQL API.</p>
</div>
<div className="rounded-2xl border border-border bg-card p-8">
<h3 className="text-xl font-bold">Advanced analytics</h3>
<p className="mt-2 text-muted-foreground">
Custom dashboards, exports, and scheduled reports.
</p>
</div>
</div>
{/* Row 3: equal thirds */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
<div className="rounded-2xl border border-border bg-card p-6 text-center">
<p className="text-3xl font-bold">10M+</p>
<p className="text-sm text-muted-foreground">Requests per day</p>
</div>
<div className="rounded-2xl border border-border bg-card p-6 text-center">
<p className="text-3xl font-bold">99.99%</p>
<p className="text-sm text-muted-foreground">Uptime SLA</p>
</div>
<div className="rounded-2xl border border-border bg-card p-6 text-center">
<p className="text-3xl font-bold">150+</p>
<p className="text-sm text-muted-foreground">Countries served</p>
</div>
</div>
</div>
);
}
This approach is easier to reason about than spanning in a single grid because each row is independent. It also collapses gracefully to a single column on mobile.
3. Animated Reveal Bento
Combine the basic grid with Framer Motion staggered entrance animations:
"use client";
import { motion } from "motion/react";
const container = {
hidden: {},
visible: { transition: { staggerChildren: 0.06 } },
};
const card = {
hidden: { opacity: 0, scale: 0.95, y: 12 },
visible: {
opacity: 1,
scale: 1,
y: 0,
transition: { duration: 0.4, ease: [0.16, 1, 0.3, 1] },
},
};
export function BentoAnimated({ items }: { items: { title: string; span?: string }[] }) {
return (
<motion.div
variants={container}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-80px" }}
className="mx-auto grid max-w-6xl grid-cols-2 gap-4 px-4 md:grid-cols-4"
>
{items.map((item) => (
<motion.div
key={item.title}
variants={card}
className={`rounded-2xl border border-border bg-card p-6 ${item.span ?? ""}`}
>
<h3 className="font-semibold">{item.title}</h3>
</motion.div>
))}
</motion.div>
);
}
Pass span: "col-span-2 row-span-2" on the items that should be larger. The stagger delay of 0.06s creates a rapid cascade effect that feels dynamic without being slow.
4. Draggable Bento
An interactive variant where users can reorder cards. This uses Framer Motion's Reorder component:
"use client";
import { Reorder } from "motion/react";
import { useState } from "react";
interface BentoItem {
id: string;
title: string;
description: string;
}
export function BentoDraggable({ initialItems }: { initialItems: BentoItem[] }) {
const [items, setItems] = useState(initialItems);
return (
<Reorder.Group
axis="y"
values={items}
onReorder={setItems}
className="mx-auto grid max-w-4xl gap-4 px-4"
>
{items.map((item) => (
<Reorder.Item
key={item.id}
value={item}
className="cursor-grab rounded-2xl border border-border bg-card p-6 active:cursor-grabbing"
>
<h3 className="font-semibold">{item.title}</h3>
<p className="mt-1 text-sm text-muted-foreground">{item.description}</p>
</Reorder.Item>
))}
</Reorder.Group>
);
}
Draggable bento is ideal for dashboards, onboarding flows, or interactive demos on landing pages where you want to showcase customizability.
5. Neon Glow Bento
For dark-themed landing pages, add a subtle glow effect to card borders on hover:
export function BentoNeon() {
return (
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
<div
className="group relative col-span-2 row-span-2 overflow-hidden rounded-2xl border border-neutral-800 bg-neutral-950 p-8 transition-colors hover:border-blue-500/50"
>
{/* Glow effect */}
<div className="pointer-events-none absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100">
<div className="absolute -inset-1 bg-blue-500/10 blur-xl" />
</div>
<div className="relative">
<h3 className="text-xl font-bold text-white">AI-Powered Search</h3>
<p className="mt-2 text-neutral-400">
Natural language queries across your entire workspace.
</p>
</div>
</div>
{/* Additional cards with different glow colors */}
<div className="group relative overflow-hidden rounded-2xl border border-neutral-800 bg-neutral-950 p-6 transition-colors hover:border-purple-500/50">
<div className="pointer-events-none absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100">
<div className="absolute -inset-1 bg-purple-500/10 blur-xl" />
</div>
<div className="relative">
<h3 className="font-semibold text-white">Automation</h3>
</div>
</div>
<div className="group relative overflow-hidden rounded-2xl border border-neutral-800 bg-neutral-950 p-6 transition-colors hover:border-green-500/50">
<div className="pointer-events-none absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100">
<div className="absolute -inset-1 bg-green-500/10 blur-xl" />
</div>
<div className="relative">
<h3 className="font-semibold text-white">Integrations</h3>
</div>
</div>
</div>
);
}
The glow is a blurred div with low opacity that fades in on hover. The group / group-hover pattern keeps the effect declarative — no JavaScript needed.
6. Text + Image Bento
A hybrid layout mixing text cards with full-bleed images:
export function BentoMedia() {
return (
<div className="mx-auto grid max-w-6xl grid-cols-2 gap-4 px-4 md:grid-cols-4">
{/* Text card — 2 columns */}
<div className="col-span-2 rounded-2xl border border-border bg-card p-8">
<h3 className="text-xl font-bold">Designed for developers</h3>
<p className="mt-2 text-muted-foreground">
First-class TypeScript support, comprehensive API docs, and a CLI that stays out of your way.
</p>
</div>
{/* Image card — 2 columns */}
<div className="col-span-2 overflow-hidden rounded-2xl border border-border">
<img
src="/dashboard-screenshot.png"
alt="Dashboard screenshot"
className="h-full w-full object-cover"
/>
</div>
{/* Full-width image row */}
<div className="col-span-2 overflow-hidden rounded-2xl border border-border md:col-span-4">
<img
src="/workflow-diagram.png"
alt="Workflow automation diagram"
className="h-64 w-full object-cover"
/>
</div>
</div>
);
}
The combination of text and image cards breaks up visual monotony and lets you show the product in context alongside feature descriptions.
Browse More Bento Layouts
These six patterns cover the most common bento grid use cases, but there are many more variations — gradient backgrounds, icon-heavy layouts, stat counters, and interactive demos. The Incubator catalog has a dedicated collection of bento grid sections, all built with Tailwind CSS and ready to copy into your React project. Each variant includes responsive behavior, dark mode support, and optional Framer Motion animations. Browse the full catalog to find the layout that fits your landing page.