Skip to content
GetUrUI

Bento grid layout: a design and code guide for React

A bento grid packs a few ideas into tiles of different sizes, like the compartments of a bento box. This guide covers what makes one work, the CSS behind it, a Tailwind and React version, and real examples you can install.

By GetUrUI team7 min read

The examples in this guide are our own products. Feature Grid is free and MIT licensed, Bento Showcase is part of GetUrUI Pro, and templates are sold separately.

What is a bento grid?

A bento grid is a layout of rectangular tiles of different sizes, arranged on a regular grid with even gaps. The name comes from the Japanese bento box, where one box holds several dishes in compartments of different sizes. In web design, each tile holds one idea: a feature, a number, a screenshot, a quote.

Product launch pages and keynote-style feature slides made the look familiar, and it is now common on SaaS landing pages, portfolios and dashboards. Underneath, a bento grid layout is ordinary CSS Grid: some tiles span more columns or rows than others, and that difference in size tells the reader what matters most.

When a bento grid works, and when it doesn't

A bento grid is a good fit when you have a small, known set of things to show and they are not all equally important:

  • A features section on a landing page: one headline feature and four or five supporting ones.
  • A hero section that shows a product from several angles at once.
  • A portfolio or about page with a few projects, a photo and a short bio.
  • A dashboard overview where one chart leads and smaller stats sit around it.

It is a poor fit for long or unknown lists (search results, a blog archive, a product catalogue), for content where every item has equal weight, and for text-heavy material that people read top to bottom. A plain card grid or a list does those jobs better.

Bento grid vs masonry

Bento gridMasonryCard grid
Tile sizesChosen by you, spanning columns and rowsEqual width, height set by the contentAll the same
Best forA few curated items with a clear leadGalleries of images with unknown heightsLong lists of equal items
OrderFixed and designedFlows column by columnRow by row
Built withCSS Grid spansCSS columns or JavaScriptCSS Grid

In short: masonry adapts to whatever content arrives, while a bento grid is designed around content you already know. If your content is the first kind, read our masonry layout guide instead.

Bento grid design rules

Most bento grids that feel off break one of these rules. They apply whether you design in a tool first or straight in code.

  1. One hero tile. Give the most important idea the largest tile. If two tiles compete for attention, neither wins.
  2. Five to seven tiles. Fewer looks like a broken card grid; more turns into a wall the eye can't scan.
  3. Size by importance, not by variety. A tile is large because its content matters, not to make the layout look interesting.
  4. One idea per tile. A short title, one supporting line and one visual. If a tile needs a paragraph, it belongs in a section of its own.
  5. Even gaps and radii. Use the same gap everywhere and one corner radius. For nested elements, inner radius = outer radius − padding, so curves stay parallel.
  6. Reading order matches visual order. Screen readers and keyboard users follow the DOM, so put tiles in the source in the order a sighted reader would scan them.
  7. Works in both themes. Tiles need to stand apart from the page background in dark and light mode: a lifted surface colour and a hairline border usually do it.

Build a bento grid layout in CSS

Start with a fixed number of columns and let tiles span them. grid-auto-rows gives every row a minimum height, so a tile that spans two rows is exactly twice as tall as its neighbours plus one gap.

bento.css
1.bento {
2  display: grid;
3  grid-template-columns: repeat(4, minmax(0, 1fr));
4  grid-auto-rows: minmax(180px, auto);
5  gap: 16px;
6}
7
8/* The hero tile takes two columns and two rows. */
9.bento > .tile-hero { grid-column: span 2; grid-row: span 2; }
10/* A wide tile takes two columns, one row. */
11.bento > .tile-wide { grid-column: span 2; }
12
13.tile {
14  border: 1px solid var(--border);
15  border-radius: 20px;
16  padding: 24px;
17  background: var(--surface);
18}

That is the whole technique. Four columns with a 2 × 2 hero, two single tiles and one wide tile fill two rows exactly. If your tiles leave holes, grid-auto-flow: dense will backfill them, but it does so by moving tiles out of source order, which breaks rule 6 above. Fix the spans instead.

The same bento grid in Tailwind CSS and React

In a React or Next.js app with Tailwind CSS 4, the same layout is a few utility classes. This version uses container queries (@container, @2xl:, @4xl:) rather than screen breakpoints, so the grid adapts to the space it is given: full width on a landing page, or a narrow column next to a sidebar.

bento.tsx
1type Tile = { title: string; body: string; span: string };
2
3// Full class names, written out: Tailwind only generates classes it can find in your source,
4// so `col-span-${n}` built at runtime would never get styles.
5const tiles: Tile[] = [
6  { title: "Ship faster", body: "One command adds a whole section.", span: "@2xl:col-span-2 @4xl:row-span-2" },
7  { title: "Dark and light", body: "Every tile reads in both themes.", span: "" },
8  { title: "Keyboard first", body: "Focus rings you can see.", span: "" },
9  { title: "Own the code", body: "The source lands in your repo.", span: "@2xl:col-span-2" },
10];
11
12export function Bento() {
13  return (
14    <section className="@container">
15      <div className="grid grid-cols-1 gap-4 @2xl:grid-cols-2 @4xl:auto-rows-[200px] @4xl:grid-cols-4">
16        {tiles.map((t) => (
17          <article key={t.title} className={`rounded-2xl border border-border bg-surface p-6 ${t.span}`}>
18            <h3 className="font-semibold text-ink">{t.title}</h3>
19            <p className="mt-1 text-sm text-ink-muted">{t.body}</p>
20          </article>
21        ))}
22      </div>
23    </section>
24  );
25}

Each tile is an article with a real heading, so the section has a sensible outline for assistive technology and for search engines. GetUrUI's own bento blocks are built the same way.

How we built our bento grids

We ship two bento blocks, and the rules above come from building them. Here is what each one does, taken straight from the source you install.

Feature Grid: six tiles on three columns

At full width the grid has three columns, and tiles 1 and 6 span two. That gives three rows of exactly three columns each (2 + 1, 1 + 1 + 1, 1 + 2), so there are no holes to patch. Each tile runs its animation only while it is on screen (Motion's useInView), and under reduced motion it stops.

Bento Showcase: five cards on twelve columns

Five cards of unequal width don't divide evenly into three or four columns, so the wide layout uses twelve. The lead card takes 7 columns and 2 rows, the next two take 5 each beside it, and the last row splits 4 + 8. Every row adds up to 12. On medium containers it drops to two columns with the lead card across both, and on small ones to a single column.

Choices we made in both

  • Container queries, not screen breakpoints. Both blocks are wrapped in @container, so they lay out by the space they get. The same block works full width on a landing page and inside a narrower docs column.
  • No grid-auto-flow: dense. We size the spans so the rows fill exactly, which keeps the visual order and the source order the same.
  • Hover is also focus. In Bento Showcase, focusing a linked card with the keyboard plays its illustration the same way hovering does.
  • Real headings. Every tile's title is a heading, and the illustrations are aria-hidden.

Make a bento grid responsive

A responsive bento grid doesn't try to keep the desktop shape on a phone. Collapse it in steps: one column on phones, two on tablets, the full bento on wide screens. Drop the row spans on small screens, or the hero tile turns into a tall empty box.

bento-responsive.css
1/* Phones: one column, tiles in reading order, no spans. */
2.bento { grid-template-columns: 1fr; }
3.bento > * { grid-column: auto; grid-row: auto; }
4
5/* Tablets: two columns; only the hero spans. */
6@media (min-width: 640px) {
7  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
8  .bento > .tile-hero { grid-column: span 2; }
9}
10
11/* Desktop: the full four-column bento. */
12@media (min-width: 1024px) {
13  .bento { grid-template-columns: repeat(4, minmax(0, 1fr)); }
14  .bento > .tile-hero { grid-column: span 2; grid-row: span 2; }
15  .bento > .tile-wide { grid-column: span 2; }
16}
  • Keep the hero tile first in the source, so it is also first on mobile.
  • Check that no tile is taller than a phone screen once it is a single column.
  • Prefer container queries for blocks that can appear in different layouts; use media queries for page-level grids.
  • Test the in-between widths, around 700 to 900px, where two-column layouts tend to leave a lonely tile.

Hover and animation without hurting accessibility

Motion is a big part of why bento grids feel alive: a tile lifts on hover, an illustration plays, a number counts up. A few rules keep that from getting in the way:

  • Decorative art is aria-hidden. The tile's heading and text carry the meaning; the animation is extra.
  • Hover effects also run on keyboard focus, so they aren't mouse-only.
  • Respect prefers-reduced-motion. Show the end state instead of the animation.
  • Animate only what's on screen. Start loops when a tile scrolls into view and stop them when it leaves.
  • Animate transform and opacity, not layout properties, so scrolling stays smooth.
tile-art.tsx
1import { motion, useReducedMotion } from "motion/react";
2
3export function TileArt() {
4  const reduce = useReducedMotion();
5  return (
6    <motion.div
7      aria-hidden
8      initial={{ opacity: 0, y: 8 }}
9      whileInView={{ opacity: 1, y: 0 }}
10      // Under reduced motion the art simply appears in its end state.
11      transition={reduce ? { duration: 0 } : { type: "spring", stiffness: 260, damping: 28 }}
12      viewport={{ once: true }}
13    />
14  );
15}

Bento grid examples you can install

These bento grid examples are all from GetUrUI and installed as source with the shadcn CLI, so the code lives in your repo and you can change anything. Each one is tagged Free or Pro.

Six tiles; the first and last span two columns. Each tile runs a small live animation while it is in view (a typing command, a theme toggle, a rolling counter) and stops entirely under reduced motion. MIT licensed. Feature Grid docs
$npx shadcn@latest add @geturui/feature-grid
An asymmetric five-card bento on a 12-column grid with a large lead card. Hovering or focusing a card plays its illustration, and a card with a link becomes one focusable target with a nudging arrow. Bento Showcase docs
$npx shadcn@latest add @geturui-pro/bento-showcase

Bento grids inside full templates

Templates are sold one at a time, or all together with a Lifetime plan. They are not part of Pro. Each of these landing pages has a bento section you can study in the live preview:

Install a bento grid with the shadcn CLI

Add the theme tokens once, then the block. Free items come from the @geturui registry; Pro items come from @geturui-pro and need your registry token. See Installation and Pro registry for the components.json setup.

terminal
1npx shadcn@latest add @geturui/theme
2npx shadcn@latest add @geturui/feature-grid        # Free
3npx shadcn@latest add @geturui-pro/bento-showcase  # Pro, needs GETURUI_TOKEN

Both blocks take their tiles as props, so you replace the copy and illustrations without touching the layout. The Feature Grid and Bento Showcase docs list every prop.

FAQ

What does bento grid mean in UI design?

It is a layout of tiles of different sizes on one grid, named after the compartments of a Japanese bento box. Each tile holds one idea, and the biggest tile holds the most important one.

Is a bento grid just CSS Grid?

Yes. A bento grid is CSS Grid with grid-column and grid-row spans. No library is needed for the layout itself; libraries help with the tiles' content and animation.

How do I make a bento grid responsive?

Collapse it in steps: one column on phones, two on tablets and the full layout on wide screens, removing row spans on small screens. Container queries let a bento block adapt to its own width.

Is there a free bento grid component for React?

Yes. GetUrUI's Feature Grid is a free, MIT-licensed animated bento grid for React and Tailwind CSS, installed with npx shadcn@latest add @geturui/feature-grid.

Sources