Components
Bento Grid
A container component that establishes a CSS Grid for creating "bento box" layouts.
Installation
CLI
Installation via the CLI is coming soon. For now, please follow the manual installation instructions below.
Manual
Install the necessary dependencies:
npm install tailwind-merge
yarn add tailwind-merge
pnpm add tailwind-merge
Copy and paste the following code into your project:
import React from 'react';
import { twMerge } from 'tailwind-merge';
type BentoGridProps = {
/** The child `BentoItem` components to be rendered within the grid. */
children: React.ReactNode;
/** Optional classes to apply to the grid container for custom styling. */
className?: string;
/** The total number of columns in the grid. */
columns?: number;
/** The total number of rows in the grid. If provided, the grid will have a fixed height. */
rows?: number;
};
/**
* A container component that establishes a CSS Grid for creating "bento box" layouts.
* It dynamically sets the grid structure based on the provided `columns` and optional `rows` props.
*/
export const BentoGrid = ({
children,
className,
columns = 12,
rows,
}: BentoGridProps) => {
const gridStyle = {
'--bento-grid-cols': columns.toString(),
...(rows && { '--bento-grid-rows': rows.toString() }),
} as React.CSSProperties;
return (
<div
style={gridStyle}
className={twMerge(
'grid w-full gap-4',
'grid-cols-[repeat(var(--bento-grid-cols),_minmax(0,_1fr))]',
// DECISION: Allow the grid to be either explicit or implicit.
// If `rows` is provided, we create a grid with a fixed number of rows of equal height.
// If not, we fall back to `auto-rows`, allowing the grid to grow vertically as needed.
rows
? 'grid-rows-[repeat(var(--bento-grid-rows),_minmax(0,_1fr))]'
: 'auto-rows-[8rem]',
className
)}
>
{children}
</div>
);
};
type BentoItemProps = {
/** The content to be displayed inside the bento item. */
children: React.ReactNode;
/** Optional classes to apply to the item for custom styling. */
className?: string;
/** The number of columns the item should span. */
colSpan?: number;
/** The number of rows the item should span. */
rowSpan?: number;
/** The column line where the item should begin. */
colStart?: number;
/** The row line where the item should begin. */
rowStart?: number;
};
/**
* A component representing a single item or "cell" within a `BentoGrid`.
* Its position and size are controlled via span and start props.
*/
export const BentoItem = ({
children,
className,
colSpan = 1,
rowSpan = 1,
colStart,
rowStart,
}: BentoItemProps) => {
const itemStyle = {
'--bento-col-span': colSpan.toString(),
'--bento-row-span': rowSpan.toString(),
...(colStart && { '--bento-col-start': colStart.toString() }),
...(rowStart && { '--bento-row-start': rowStart.toString() }),
} as React.CSSProperties;
return (
<div
style={itemStyle}
className={twMerge(
'bg-[#1C1C1C] rounded-2xl shadow-sm border border-zinc-800 p-6',
'col-[span_var(--bento-col-span)_/_span_var(--bento-col-span)]',
'row-[span_var(--bento-row-span)_/_span_var(--bento-row-span)]',
colStart && 'col-start-[var(--bento-col-start)]',
rowStart && 'row-start-[var(--bento-row-start)]',
'flex flex-col',
className
)}
>
{children}
</div>
);
};
Usage
Import BentoGrid
and BentoItem
to create a dynamic, non-uniform grid layout.
import { BentoGrid, BentoItem } from '@/components/ui/bento-grid';
export default function BentoGridDemo() {
return (
<BentoGrid columns={8} className='max-w-4xl mx-auto'>
<BentoItem colSpan={5} rowSpan={2}>
<div className='flex flex-col h-full p-2'>
<h3 className='font-bold text-lg'>Main Feature</h3>
<p className='text-sm text-zinc-400'>
This item takes up more space.
</p>
</div>
</BentoItem>
<BentoItem colSpan={3}>
<div className='flex flex-col h-full p-2'>
<h3 className='font-bold'>Sidebar Item</h3>
</div>
</BentoItem>
<BentoItem colSpan={3} rowSpan={2}>
<div className='flex flex-col h-full p-2'>
<h3 className='font-bold text-lg'>Tall Item</h3>
<p className='text-sm text-zinc-400'>Spans multiple rows.</p>
</div>
</BentoItem>
<BentoItem colSpan={5}>
<div className='flex flex-col h-full p-2'>
<h3 className='font-bold'>Footer Item</h3>
</div>
</BentoItem>
</BentoGrid>
);
}
Props
BentoGrid
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | Required | The child BentoItem components to be rendered within the grid. |
className | string | - | Optional classes to apply to the grid container for custom styling. |
columns | number | 12 | The total number of columns in the grid. |
rows | number | - | The total number of rows in the grid. If provided, the grid will have a fixed height. |
BentoItem
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | Required | The content to be displayed inside the bento item. |
className | string | - | Optional classes to apply to the item for custom styling. |
colSpan | number | 1 | The number of columns the item should span. |
rowSpan | number | 1 | The number of rows the item should span. |
colStart | number | - | The column line where the item should begin. |
rowStart | number | - | The row line where the item should begin. |