Fylgja Bento Grid

A bento grid arranges cards of different sizes into one tidy block, like the compartments of a bento box. It suits feature overviews and landing pages, where one tile leads and smaller ones support it. The grid is a plain <ul>, so the tiles stay a real list for assistive tech.

Preview

  • A deer standing in a misty forest

    Classless base

    Native elements look right out of the box, so most markup needs no classes at all.

  • Design tokens

    Colors, shadows, and easings as CSS variables you can pick from.

  • Utilities

    Layout helpers driven by variables.

  • No build step

    Import the CSS and go.

  • Pick what you need

    Every package works on its own, so you only ship the parts your project uses.

<ul role="list" class="grid-cols gap" style="--sm_grid-cols: 2; --md_grid-cols: 4">
	<li class="card flex-col" style="--sm_col: span 2; --md_row: span 2">
		<img
			src="/images/placeholders/deer-wide.webp"
			alt="A deer standing in a misty forest"
			width="960"
			height="640"
			loading="lazy"
			class="object-cover w-full flex-auto"
			style="--size-y: 12rem"
		/>
		<div class="card-content">
			<h3 class="lead">Classless base</h3>
			<p>Native elements look right out of the box, so most markup needs no classes at all.</p>
		</div>
	</li>
	<li class="card" style="--sm_col: span 2">
		<h3 class="lead">Design tokens</h3>
		<p>Colors, shadows, and easings as CSS variables you can pick from.</p>
	</li>
	<li class="card">
		<h3 class="lead">Utilities</h3>
		<p>Layout helpers driven by variables.</p>
	</li>
	<li class="card">
		<h3 class="lead">No build step</h3>
		<p>Import the CSS and go.</p>
	</li>
	<li class="card" style="--sm_col: span 2; --md_col: span 4">
		<h3 class="lead">Pick what you need</h3>
		<p>Every package works on its own, so you only ship the parts your project uses.</p>
	</li>
</ul>

Usage

  • Wrap the tiles in a <ul role="list" class="grid-cols gap">. The grid starts at one column, and --sm_grid-cols and --md_grid-cols add columns from those breakpoints up.
  • Make each tile a <li class="card">. Set --col or --row to a span (for example span 2) to size it, with a breakpoint prefix such as --md_row so the span only applies once there are enough columns.
  • Plan each row so its spans add up to the column count. Here the four column grid has a lead tile two columns wide and two rows tall, and a full width tile closes it off.
  • For a tile with an image, make the card flex-col and give the image flex-auto and object-cover, so it fills whatever height the row span gives it. Put the text in a .card-content wrapper.

Anatomy

Part Responsibility
<ul class="grid-cols gap"> The grid, with the column count per breakpoint.
<li class="card"> A tile, sized with --col and --row spans.
.card-content Padding wrapper for the text when the tile has media.

Accessibility

  • Keep the visual order and the source order the same. Reordering tiles with grid placement makes keyboard and screen reader order jump around the page.
  • Give each tile a real heading so it shows up in the document outline.
  • Give images a descriptive alt, or alt="" when they are purely decorative.

Related: Card, Gallery, Product Grid.

FAQ

How do I make a tile wider or taller?

Set --col or --row on the tile to a grid span, such as span 2. Prefix the variable with a breakpoint (--sm_col, --md_row) to apply the span only from that screen size up, which keeps every tile full width on phones.

Why does the grid start with one column?

grid-cols defaults to a single column. The --sm_grid-cols and --md_grid-cols variables add columns as the screen grows, so small screens get a simple stack without any media queries in your markup.

Why is there a gap in my grid?

Grid places tiles in source order, so a wide tile that does not fit at the end of a row moves down and leaves a hole. Make the spans in each row add up to the column count, or reorder the tiles.

Should I use auto-grid instead?

Use auto-grid when every item is the same size and the column count should follow the width. A bento grid needs a fixed column count, because spans only line up when you know how many columns there are.