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
// Web Component (registers kittl-masonry-grid)
import '@kittl/ui';
// Or tree-shake the element only:
import '@kittl/ui/MasonryGrid';
// React
import { MasonryGrid } from '@kittl/ui-react';
Usage
Web Component
Place element nodes as direct children. The host assigns slot names so each child projects into a column.
<kittl-masonry-grid column-count="3">
<article>First cell</article>
<article>Second cell</article>
<article>Third cell</article>
</kittl-masonry-grid>
Example — 300px tile plus nine 100px tiles (add box-sizing:border-box and width:100% on tiles if you rely on borders or padding):
<kittl-masonry-grid column-count="3" style="width:100%">
<div style="height:300px">1</div>
<div style="height:100px">2</div>
<div style="height:100px">3</div>
<div style="height:100px">4</div>
<div style="height:100px">5</div>
<div style="height:100px">6</div>
<div style="height:100px">7</div>
<div style="height:100px">8</div>
<div style="height:100px">9</div>
<div style="height:100px">10</div>
</kittl-masonry-grid>
React
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.
<MasonryGrid columnCount={3}>
{items.map((item) => (
<Card key={item.id}>{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 (minimum applied: 1) |
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.