/ Docs

Grid #

PublishedUpdated Sep 16, 2026

Converts a vertical list into a 2D grid layout.

import { createVList, grid } from "vlist";

const list = createVList({
  container: "#app",
  item: { height: 120, template: renderCard },
  items: data,
}, [grid({ columns: 3, gap: 8 })]);

Config #

Option Type Default Description
columns number required Number of columns (>= 1)
gap number 0 Space between cells (px)

Aspect Ratios #

Use the columnWidth context to create responsive aspect ratios that adapt when the container resizes:

const list = createVList({
  container: "#app",
  item: {
    height: (_index, { columnWidth }) => Math.round(columnWidth * 0.75), // 4:3
    template: renderCard,
  },
  items: photos,
}, [grid({ columns: 3, gap: 8 })]);

Common ratios: * 1 (square), * 0.75 (4:3), * (9/16) (16:9), * (4/3) (3:4 portrait).

Static height: 120 values break aspect ratios on resize — always use the function form for responsive grids.

Responsive Columns #

Update the column count dynamically based on viewport width:

const updateColumns = () => {
  const w = window.innerWidth;
  const cols = w < 480 ? 2 : w < 768 ? 3 : w < 1200 ? 4 : 5;
  list.updateGrid({ columns: cols });
};

window.addEventListener("resize", updateColumns);

Methods #

Method Returns Description
getGridLayout() GridLayout Grid layout instance (see below)
updateGrid(config) void Update columns and/or gap dynamically

GridLayout properties and methods:

Member Type Description
columns number Current column count
gap number Current gap
getRow(index) number Row for item index
getCol(index) number Column for item index
getTotalRows(total) number Total row count
getColumnWidth(containerWidth) number Computed column width

CSS Classes #

  • .vlist--grid on root
  • .vlist-grid-item on items

Large datasets #

Native content stops at the browser's element size limit, about 16 million pixels. A grid past it needs nothing extra: with the default scroll.mode: "auto" the list hands its input to synthetic scrolling in place when it grows that large, and the grid positions rows relative to the scroll origin. A synthetic list draws its own scrollbar.

import { createVList, grid } from "vlist";

const list = createVList({
  container: "#app",
  item: { height: 120, template: renderCard },
  items: millionItems,
}, [grid({ columns: 4, gap: 8 })]);

scroll: { mode: "synthetic" } makes the grid synthetic from the start. See Scroll modes.

Notes #

  • Keyboard nav: arrows move in 2D (left/right between columns, up/down between rows)
  • Grids past the browser size limit go synthetic by themselves (scroll.mode: "auto")
  • Conflicts with: masonry, table

Examples #