MasonryGrid
Multi-column layout that places direct element children using shortest-column packing: each tile goes on the column with the least stacked height after measurement (including gaps). Items are still declared in DOM order; only which column they appear in changes. Composition uses kittl-masonry-column internally.
The live preview uses three columns with one 300px-tall cell and nine 100px cells. --spacing-8:0 removes gaps so column packing is easy to read; by default the grid uses 8px gaps between tiles and columns.
Import
// Registers kittl-masonry-grid
import '@kittl/ui';
// Or tree-shake the element only:
import '@kittl/ui/MasonryGrid';
import { MasonryGrid } from '@kittl/ui-react';
Usage
Place element nodes as direct children. The host assigns slot names so each child projects into a column. Add box-sizing:border-box and width:100% on tiles if you rely on borders or padding.
Composition only: map your data (or wrap static nodes), set a stable key on each sibling, and pass them as children. Same behavior as placing elements under <kittl-masonry-grid> in HTML.
<kittl-masonry-grid column-count="3" style="width:100%">
<div style="height:120px">1</div>
<div style="height:60px">2</div>
<div style="height:60px">3</div>
<div style="height:60px">4</div>
<div style="height:60px">5</div>
<div style="height:60px">6</div>
</kittl-masonry-grid>
import { Card, MasonryGrid } from '@kittl/ui-react';
const items = [
{ id: 'a', title: 'Posters', height: 120 },
{ id: 'b', title: 'Logos', height: 60 },
{ id: 'c', title: 'Stickers', height: 60 },
{ id: 'd', title: 'T-shirts', height: 60 },
{ id: 'e', title: 'Mugs', height: 60 },
{ id: 'f', title: 'Cards', height: 60 },
];
/** Basic MasonryGrid usage, rendered live on the docs site. */
export const MasonryGridUsage = () => (
<MasonryGrid columnCount={3} style={{ width: '100%' }}>
{items.map((item) => (
<Card key={item.id} style={{ height: item.height }}>
{item.title}
</Card>
))}
</MasonryGrid>
);
Tree-shake the binding only:
import { MasonryGrid } from '@kittl/ui-react/MasonryGrid';
Props / attributes
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
columnCount | column-count | number | 2 | Number of columns to distribute children across |
Shadow DOM
part="root"— row flex wrapper for columns (uses design-token gap viakittl-masonry-column).
Layout notes
- On first paint the host omits
layout-readyuntil the first successful shortest-column pass, then reveals the grid with a short opacity transition (avoids a visible jump from seeding new slots). The attribute resets when the element reconnects orcolumn-countchanges—it is not cleared when you append more tiles (e.g. infinite scroll), so the grid does not blink on each batch. A stable empty grid setslayout-readyon aqueueMicrotaskboundary so synchronous child inserts in the same turn are still measured before reveal. Tile slots are reseeding only for children that lack a validc-*for the current column count; existing packed items keep their slots until the shortest-column pass rebalances. - Placement is height-aware and reflows on resize or when tile size changes (for example images loading). Visual order is no longer strict left-to-right by DOM index—labels 1–10 may appear in different columns than a simple round-robin would place them.
- Uneven column bottoms can still happen with indivisible tile heights; shortest-column only minimizes that gap.
- Use light-DOM element children only; avoid relying on raw text nodes between items.