Masonry
A masonry container arranges variable-height children in vertical columns using CSS multi-column layout, producing a Pinterest-style staggered grid without requiring JavaScript-based positioning.
Use it for image galleries, photo packs, card boards, and any collection of items whose heights differ and where you want the layout to fill column gaps naturally.
Example
Show demo markup
<div class="masonry" aria-label="a masonry layout container for variable-height items">Masonry</div>
Usage example
<script lang="ts">
import Masonry from './Masonry.svelte';
</script>
<Masonry columns={3} gap="1rem">
<article>Short</article>
<article>Tall content here, much longer than the others.</article>
<article>Medium length</article>
</Masonry>
Show Svelte source
// In your Svelte component:
import Masonry from "lily-design-system-svelte-headless/components/Masonry/Masonry.svelte";
<Masonry>
<!-- content -->
</Masonry>
Usage
Default three-column masonry:
<Masonry>
<Card>...</Card>
<Card>...</Card>
<Card>...</Card>
</Masonry>
Two columns with larger gap:
<Masonry columns={2} gap="2rem">
<PhotoPack>...</PhotoPack>
<PhotoPack>...</PhotoPack>
</Masonry>
Props
columns: number (default: 3) -- number of columns
gap: string (default: "1rem") -- gap CSS value
children: slot -- masonry items
...restProps: any additional HTML attributes
Keyboard Interactions
- None -- this is a layout container; focusable children manage their own keyboard behavior.
ARIA
- None — purely structural.
When to Use
- Use for grids of variable-height items where uniform rows are not required.
- Use for galleries, photo packs, and card boards where natural column packing reads better than a strict grid.
When Not to Use
- Do not use when items must align across rows (use Grid).
- Do not use when item order across rows must be strictly left-to-right (CSS columns flow top-down within each column, which can be surprising).
- Do not use for one-dimensional stacks (use FlexStack).
Headless
Provides only the column-count layout via inline styles. Item-level break-inside behavior, sizing, and visual treatment are the consumer's responsibility.
Styles
A typical consumer adds break-inside: avoid to direct children:
.masonry > * {
break-inside: avoid;
margin-bottom: 1rem;
}
Testing
- Verify the component renders a
<div> element with class masonry
- Verify inline style sets
column-count to the columns prop
- Verify inline style sets
column-gap to the gap prop
- Verify
data-columns attribute matches the columns prop
- Verify children content is rendered
Advice
- Designers: CSS-columns masonry flows top-down within each column. If left-to-right reading order matters, use Grid instead.
- Developers: Always pair Masonry with
break-inside: avoid on the items so cards do not split across columns. Consider responsive overrides on column-count for narrow viewports.
Implementation Notes
- Renders a
<div> with class="masonry"
- Applies inline style
column-count: {columns}; column-gap: {gap};
- Sets
data-columns={columns} for consumer CSS hooks
- Children should set
break-inside: avoid (or page-break-inside: avoid) via consumer CSS to prevent splits across columns
- Source order determines fill order (top-down within each column)
Related components
grid — a CSS grid layout container with configurable columns and gap
flex-stack — a flex layout container for vertical or horizontal stacking with consistent gap
References
- MDN column-count: https://developer.mozilla.org/en-US/docs/Web/CSS/column-count
- MDN break-inside: https://developer.mozilla.org/en-US/docs/Web/CSS/break-inside
Canonical contract
Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata
- Component: masonry
- PascalCase: Masonry
- Description: a masonry layout container for variable-height items
- Status: beta — implemented and unit-tested in all seven frameworks with an axe-clean demo page; not yet exercised in composed flows
- HTML tag: <div>
- CSS class: .masonry
- Interactive: no
ARIA
Keyboard
- None — focusable children manage their own keyboard behavior
Props
columns: number (default: 3) -- number of columns gap: string (default: "1rem") -- gap CSS value children: slot -- masonry items ...restProps: any additional HTML attributes