Masonry
A masonry layout container based on CSS columns; child items are automatically distributed across columns without being split.
Basic Usage
Four-column masonry
Short card
This is taller content, showing how cards of different heights are staggered in a masonry layout; a few more lines are added to increase the height.
A second paragraph.
Medium height
Additional notes.
Another short card
A taller card with multiple lines of description and a list.
- Point 1
- Point 2
Normal card
An example in the last column.
Columns and Gap
Three columns, larger gap
Item A
Item B; the masonry auto-fills when heights differ.
Item C
Item D
Responsive Columns
1 column at base, 2 at md, 4 at lg
Narrow the browser window to watch the column count switch between 1 → 2 → 4.
Breakpoints: `sm`=640px / `md`=768px / `lg`=1024px / `xl`=1280px (mobile-first min-width); below a breakpoint the base value applies.
A third card, demonstrating the multi-column distribution.
A fourth card.
A fifth card; children reflow automatically when the column count changes, no JS involved.
A sixth card.
Row / Column Gap
Row gap 12, column gap 24
Row gap 12px (children's margin-bottom), column gap 24px (column-gap); two values separated by a space: `gap="row col"`.
Item B.
Item C.
Item D.
Item E.
fresh Continuous Reflow
fresh: watch child size changes
With `fresh`, the component keeps listening for child size changes (e.g. height changes when images arrive late) via ResizeObserver and triggers a recompute on each change.
Item B.
Item C, taller.
Additional notes.
Item D.
Item E.
Under the CSS columns implementation the browser already reflows children when their size changes; `fresh` guarantees an extra recompute opportunity (semantic alignment and a hook for a future JS-based layout).
Pin Children to a Column
Specify the target column of children
This card has `column="2"` and is reordered into column 2.
This card has `column="4"` and is reordered into column 4.
Normal card A, auto-filled.
Normal card B.
Normal card C.
Normal card D.
Normal card E.
A child's `column` (1-based) pins it to a column; values beyond the current column count or non-numeric values are ignored (with a dev warning). When used with responsive columns, the reorder follows the currently effective column count.
Sequential masonry
By default items are distributed to balance column heights. With sequential, items instead fill columns in round-robin by original order — item i lands in column i % columns + 1, so the reading order advances across columns (1→col 1, 2→col 2, …, back to col 1). It is mutually exclusive with a child's column pin (sequential ignores column); when breakpoint columns change, the rotation recomputes against the currently effective column count.
sequential round-robin fill
Card 1 → top of column 1
Card 2 → top of column 2
Card 3 → top of column 3
Card 4 → back to column 1
Card 5 → column 2
Card 6 → column 3
With equal-height cards each of the three columns holds exactly two items (1/4, 2/5, 3/6); when heights vary a lot, CSS columns still balances by height — the strict round-robin holds for equal-height items.
No Children
Empty container
With no children it renders an empty container without errors.
items Data-Driven
Card flow rendered from an items JSON array
`items` is a JSON array (also assignable via `el.items = [...]` as a property): `text` renders as plain text into a card, `height` is the item's minimum height (px). When explicitly set and non-empty, items take precedence over slotted children (ignored); absent / empty array / invalid JSON fall back to the slot channel.
Pin items to a column + responsive columns
The `column` field (1-based) pins an item to a column, reusing the same reorder logic as the child `column` attribute; combined with responsive columns (`1 md:2 lg:4`) the reorder follows the currently effective column count.
API
oas-masonry
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
columns | Number of columns (default 4); supports breakpoint shorthand: a base value plus space-separated breakpoint:value pairs (e.g. 1 md:2 lg:4; breakpoints sm=640px / md=768px / lg=1024px / xl=1280px, mobile-first min-width, base below breakpoints); invalid values (non-positive integers / decimals / 0 / negatives) fall back to 1 | — | — |
fresh | Keep listening for child size changes via ResizeObserver and trigger a recompute; under the CSS columns implementation the browser already reflows automatically, so fresh is a semantic hook aligned with a future JS-based layout | boolean | — |
gap | Spacing (px, default 8). A single value sets the column gap; two values row col (e.g. 8 16) set the row gap on children's margin-bottom and the column gap; plain numbers get px appended; invalid values fall back to the default | — | — |
items | Masonry items JSON [{text, height?, column?}]; also assignable as an array property. When explicitly set and non-empty it takes precedence over slotted children (ignored); absent / empty array / invalid JSON fall back to the slot channel (invalid JSON logs a deduplicated dev warning). text is rendered safely as plain text; height is the item's minimum height (px, written to the rendered item's min-height); column pins the item to a column (1-based, same reorder logic as the child column attribute) | MasonryItem[] | string | [] |
sequential | Sequential masonry: fill columns round-robin by original order instead of height balancing; mutually exclusive with a child column pin (sequential wins) | boolean | — |
Slots
| Name | Description |
|---|---|
| default | Masonry child items; children automatically get break-inside: avoid; children with a column attribute (1-based) are reordered into the target column; when the items attribute is explicitly set and non-empty, children are ignored (items take precedence) |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-masonry-columns | ${base} |
--oas-masonry-item-gap | var(--oas-space-2) |
Child Attributes
| Child Attribute | Description |
|---|---|
column | Pin a child to a column (1-based): under the CSS columns implementation the DOM is reordered to physically move the child into the target column; with responsive columns the reorder follows the currently effective column count. Invalid values (non-integers / ≤0 / beyond the current column count) are ignored with a dev warning |
Parts: ::part(masonry) the masonry container, ::part(masonry-item) each rendered item (items channel).