Bento Grid
Asymmetric grid layout for showcasing content in varied tile sizes.
Code
components/BentoGrid.astro
---import type { ImageMetadata } from "astro"; interface BentoItem { title: string; description?: string; size?: "sm" | "md" | "lg" | "featured"; imageSrc?: ImageMetadata | string; imageOverlay?: boolean; class?: string;} interface Props { items: BentoItem[]; class?: string;} const { items, class: className = "",} = Astro.props; const sizeClasses = { sm: "md:col-span-1 md:row-span-1", md: "md:col-span-1 md:row-span-2", lg: "md:col-span-2 md:row-span-1", featured: "md:col-span-2 md:row-span-2",};--- <div class:list={["grid grid-cols-1 md:grid-cols-4 gap-3 md:gap-4 auto-rows-auto md:auto-rows-fr", className]}> {items.map((item) => { const bgUrl = item.imageSrc ? typeof item.imageSrc === "string" ? item.imageSrc : item.imageSrc.src : null; const showOverlay = item.imageSrc && item.imageOverlay !== false; return ( <div class:list={[ "rounded-xl p-5 md:p-6 flex flex-col justify-center bg-cover bg-center relative", sizeClasses[item.size || "sm"], item.imageSrc ? "text-white-ghost" : item.class || "bg-black-onyx/5 text-black-onyx", ]} style={bgUrl ? { backgroundImage: `url(${bgUrl})` } : undefined} > {showOverlay && ( <div class="absolute inset-0 bg-black-onyx/50 rounded-xl" /> )} <div class="relative z-10"> <h3 class="text-sm md:text-base font-semibold">{item.title}</h3> {item.description && ( <p class="text-xs md:text-sm mt-1 leading-relaxed opacity-80"> {item.description} </p> )} </div> </div> ); })}</div>
Preview
Default Bento Grid
Lightweight
Only 15KB minified. No bloat, no unnecessary dependencies.
Copy-Paste
No npm install. Copy the code and paste it directly.
Customizable
CSS variables for every component.
Responsive
Mobile-first design. Works on every screen size.
With Background Image
Desktop Setup
Clean workspace for focused development.
Minimal
Less is more.
Clean
Organized and tidy.
Modern
Contemporary design.
Productive
Built for efficiency.
Usage
<BentoGrid items={[ { title: "Feature A", description: "Description", size: "featured" }, { title: "Feature B", description: "Description", size: "lg" }, { title: "Feature C", description: "Description", size: "sm" }, { title: "Feature D", description: "Description", size: "sm" }, { title: "Feature E", description: "Description", size: "md" }, ]}/>
<BentoGrid items={[ { title: "With Image", description: "This card uses a background image", size: "featured", imageSrc: Desktop }, { title: "Normal", description: "Regular card", size: "sm" }, { title: "Normal", description: "Regular card", size: "sm" }, { title: "Normal", description: "Regular card", size: "sm" }, { title: "Normal", description: "Regular card", size: "md" }, ]}/>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | BentoItem[] | — | Array of grid items with title, description, size, imageSrc, and optional class. |
| class | string | — | Additional CSS classes. |
Item Fields
| Field | Type | Default | Description |
|---|---|---|---|
| title | string | — | Card title. |
| description | string | — | Optional description text. |
| size | "sm" | "md" | "lg" | "featured" | "sm" | Grid span size. |
| imageSrc | ImageMetadata | string | — | Background image (imported or URL). |
| imageOverlay | boolean | true | Dark overlay for text readability. |
| class | string | — | Custom background/text color (ignored when imageSrc is set). |
Item Sizes
| Size | Mobile | Desktop |
|---|---|---|
| sm | 1 col | 1 col × 1 row |
| md | 1 col | 1 col × 2 rows |
| lg | 1 col | 2 cols × 1 row |
| featured | 1 col | 2 cols × 2 rows |