Volver al blog

React Bento Grid: 6 layouts listos para copiar y pegar en UIs modernas

Publicado el 20 de marzo de 2026·7 min read

Los bento grids están por todas partes: Apple los usa en sus páginas de producto, Linear en su changelog, Vercel en su dashboard. El atractivo es evidente: los layouts asimétricos de tarjetas generan un interés visual que las cuadrículas uniformes nunca logran. Cada tarjeta recibe exactamente el espacio que su contenido necesita, y la composición global se siente cuidada en lugar de prefabricada.

Esta guía recorre seis patrones de bento grid en React con Tailwind CSS, desde un layout básico hasta variantes animadas e interactivas. Todos están listos para copiar y pegar.

1. Bento Grid básico

La base: un CSS Grid con grid-template-columns y utilidades de spanning. El layout parte de una cuadrícula base de 4 columnas donde las tarjetas ocupan 1 o 2 columnas y filas:

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>
  );
}

La clave está en col-span-2 row-span-2 sobre la tarjeta principal. Ocupa 4 veces el área de una tarjeta normal y crea la asimetría característica del bento.

2. Layout asimétrico

Una composición más editorial donde la cuadrícula cambia de forma de una fila a otra. En vez de una base uniforme, cada fila define su propio reparto de columnas:

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>
  );
}

Este enfoque resulta más fácil de razonar que el spanning dentro de una sola cuadrícula, porque cada fila es independiente. Además se colapsa con elegancia a una sola columna en móvil.

3. Bento con reveal animado

Combina la cuadrícula básica con animaciones de entrada escalonadas de Framer Motion:

"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>
  );
}

Pasa span: "col-span-2 row-span-2" en los items que deban ser más grandes. El retardo de stagger de 0.06s produce un efecto cascada rápido que se siente dinámico sin volverse lento.

4. Bento arrastrable

Una variante interactiva en la que el usuario puede reordenar las tarjetas. Aquí entra el componente Reorder de Framer Motion:

"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>
  );
}

El bento arrastrable es ideal para dashboards, flujos de onboarding o demos interactivas en landing pages donde quieres mostrar lo personalizable que es el producto.

5. Bento con neon glow

Para landing pages con tema oscuro, añade un sutil efecto de brillo en los bordes de las tarjetas al pasar el cursor:

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>
  );
}

El brillo es un div desenfocado con baja opacidad que aparece al pasar el cursor. El patrón group / group-hover mantiene el efecto declarativo, sin necesidad de JavaScript.

6. Bento texto + imagen

Un layout híbrido que mezcla tarjetas de texto con imágenes a sangre completa:

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>
  );
}

La combinación de tarjetas de texto e imagen rompe la monotonía visual y te deja mostrar el producto en contexto junto a las descripciones de cada feature.

Explora más layouts de bento

Estos seis patrones cubren los casos de uso más habituales de los bento grids, pero hay muchas más variantes: fondos con gradientes, layouts cargados de iconos, contadores de estadísticas y demos interactivas. El catálogo de Incubator tiene una colección dedicada a secciones de bento grid, todas construidas con Tailwind CSS y listas para copiar en tu proyecto React. Cada variante incluye comportamiento responsive, soporte para dark mode y animaciones opcionales con Framer Motion. Explora el catálogo completo para encontrar el layout que encaje con tu landing page.

Relacionado en incubator

VA

Victor Aubague

Desarrollador y creador de Incubator

Desarrollador full-stack especializado en React, Next.js y TypeScript. Creé Incubator para ayudar a los desarrolladores a lanzar interfaces bonitas más rápido, todos los componentes provienen de proyectos reales de clientes y de código en producción.

LinkedIn

Related articles

React Bento Grid: 6 layouts listos para copiar y pegar en