BentoGrid
A modern grid layout component for creating compartmentalized designs inspired by the bento box aesthetic.
Loading...
Installation
pnpm add @corew500/uiUsage
import { BentoGrid, BentoGridItem } from "@corew500/ui/bento-grid"
<BentoGrid columns={3}>
<BentoGridItem colSpan={2} rowSpan={2}>
<h3>Main Feature</h3>
<p>Large featured content</p>
</BentoGridItem>
<BentoGridItem>
<h3>Side Feature</h3>
</BentoGridItem>
<BentoGridItem>
<h3>Another Item</h3>
</BentoGridItem>
</BentoGrid>Columns
Control the number of grid columns (responsive by default).
<BentoGrid columns={1}>
{/* Single column */}
</BentoGrid>
<BentoGrid columns={2}>
{/* 2 columns on md+ screens */}
</BentoGrid>
<BentoGrid columns={3}>
{/* 3 columns on md+ screens (default) */}
</BentoGrid>
<BentoGrid columns={4}>
{/* 4 columns on lg+ screens */}
</BentoGrid>Row Heights
Control automatic row heights using design tokens.
<BentoGrid autoRows="sm">
{/* Shorter rows */}
</BentoGrid>
<BentoGrid autoRows="default">
{/* Default row height */}
</BentoGrid>
<BentoGrid autoRows="lg">
{/* Taller rows */}
</BentoGrid>Row heights are controlled by CSS variables:
--bento-row-height-sm--bento-row-height-default--bento-row-height-lg
Spanning Columns and Rows
Use colSpan and rowSpan to create complex layouts.
<BentoGrid columns={3}>
{/* Full width banner */}
<BentoGridItem colSpan={3}>
<h2>Hero Section</h2>
</BentoGridItem>
{/* 2/3 width main content */}
<BentoGridItem colSpan={2} rowSpan={2}>
<h3>Main Content</h3>
</BentoGridItem>
{/* 1/3 width sidebar items */}
<BentoGridItem>
<h4>Sidebar Item 1</h4>
</BentoGridItem>
<BentoGridItem>
<h4>Sidebar Item 2</h4>
</BentoGridItem>
</BentoGrid>Responsive Behavior
BentoGrid is mobile-first:
- Mobile: All items stack in a single column
- Tablet (md+): Grid layout with spans applied
- Desktop (lg+): 4-column grids become active
Loading State
Show skeleton placeholders while grid items are loading:
const { data, isLoading } = useQuery({ queryKey: ["items"], queryFn: fetchItems })
<BentoGrid columns={3} loading={isLoading} loadingItems={6}>
{data?.map((item, index) => (
<BentoGridItem key={index}>
<Card>
<CardContent>{item.content}</CardContent>
</Card>
</BentoGridItem>
))}
</BentoGrid>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| loading | boolean | false | Show skeleton loading state |
| loadingItems | number | 6 | Number of skeleton items to display |
| loadingItemRenderer | (index) => ReactNode | - | Custom skeleton item renderer |
Custom skeleton renderer:
<BentoGrid
columns={3}
loading
loadingItems={6}
loadingItemRenderer={(index) => (
<Card>
<CardContent className="p-4 space-y-3">
<Skeleton className="h-[150px] w-full rounded-lg" />
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-1/2" />
</CardContent>
</Card>
)}
>
{/* Content */}
</BentoGrid>API Reference
BentoGrid
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| loading | enum | false | Show skeleton loading state |
| loadingItems | number | 6 | Number of skeleton items to show when loading (default: 6) |
| loadingItemRenderer | (index: number) => ReactNode | — | Custom skeleton item renderer |
| columns | enum | — | — |
| autoRows | enum | — | — |
Accessibility
Additional
- - Uses semantic div elements; wrap in section or article as needed.
- Ensure grid items have proper heading hierarchy.
- Consider providing a skip link for long grids.
Localization
Translatable Content
- - No text content; localize grid item children as needed.
RTL Support
- Grid layout works correctly in both LTR and RTL layouts.
Related
Related Components
BentoGridItem
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| colSpan | enum | — | — |
| rowSpan | enum | — | — |