GitHub

BentoGrid

A modern grid layout component for creating compartmentalized designs inspired by the bento box aesthetic.

Loading...

Installation

pnpm add @corew500/ui

Usage

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

PropTypeDefaultDescription
loadingenumfalseShow skeleton loading state
loadingItemsnumber6Number of skeleton items to show when loading (default: 6)
loadingItemRenderer(index: number) => ReactNode—Custom skeleton item renderer
columnsenum——
autoRowsenum——

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

PropTypeDefaultDescription
colSpanenum——
rowSpanenum——

Related

Related Components