JavaScript Image List
@lemonadejs/imagelist · ✓ 14 contract checks · framework-agnostic · zero dependencies
<ImageList /> — a responsive image grid (new in v6, no v5 source).
Three layouts, all driven by deterministic inline styles (jsdom-testable):
- standard (default): CSS grid — grid-template-columns repeat(columns, 1fr), gap, and grid-auto-rows when rowheight > 0 (rowheight 0 = the rows size themselves to their content)
- masonry: CSS multi-column layout (columns: N + column-gap; items carry break-inside: avoid and the vertical gap) — ragged bottoms, natural image heights
- quilted: the standard grid, but items may span cells through item.cols / item.rows (grid-column / grid-row: span X)
Item bars (bar): a translucent overlay at the bottom of each image with the item title + optional subtitle.
Images load lazily (loading=“lazy”); the alt text is item.alt, falling back to item.title, then ”. data is held BY REFERENCE: mutate the array or its records and call data.touch() to re-render — or assign a new array. onitemclick(item, index, event) makes tiles interactive (cursor through data-clickable, plus role=“button”, tabindex and Enter/Space activation).
Example
import { html } from 'lemonadejs';
import ImageList from '@lemonadejs/imagelist';
const pic = (seed) => `https://picsum.photos/seed/${seed}/400/300`;
const photos = [
{ src: pic('breakfast'), title: 'Breakfast', subtitle: '@bkristastucchio' },
{ src: pic('camera'), title: 'Camera', subtitle: '@helloimnik' },
{ src: pic('coffee'), title: 'Coffee', subtitle: '@nolanissac' },
{ src: pic('hats'), title: 'Hats', subtitle: '@hjrc33' },
{ src: pic('fern'), title: 'Fern', subtitle: '@katie_wasserman' },
{ src: pic('honey'), title: 'Honey', subtitle: '@arwinneil' },
];
const App = (props, { state }) => {
const picked = state('none yet');
return html`<div>
<${ImageList} data="${photos}" columns="3" rowheight="140" bar
onitemclick="${(item, index) => (picked.value = `#${index + 1} ${item.title}`)}" />
<p style="font-size:13px">Clicked: <b>${picked}</b></p>
</div>`;
};Installation
npm install @lemonadejs/imagelist
import Imagelist from '@lemonadejs/imagelist';
import '@lemonadejs/imagelist/style.css';
Three deployment forms, one component:
html`<${Imagelist} />` // by value (no registration)
setComponents({ Imagelist }); // then <Imagelist /> by name anywhere
createWebComponent(Imagelist); // <lm-imagelist> in plain HTML/any framework
Props
Every declared prop arrives as a live state — pass a value for a snapshot or a state for a two-way live wire. Attribute strings are coerced to the declared type.
| Prop | Type | Default | Description |
|---|---|---|---|
data | array | — | ImageListItem[] BY REFERENCE (mutate + touch()) |
columns | number | 3 | grid columns (masonry: CSS column count) |
gap | number | 8 | px between tiles |
rowheight | number | 164 | px per grid row; 0 = natural heights |
variant | string | '' | ” standard |
bar | boolean | false | overlay title bar on each image |
Events
All event names are lowercase (the platform convention — LJS-305 warns otherwise).
onitemclick— (item, index, event)
Styling
All classes follow the lm-imagelist-* convention; visual variants are data-*
attributes on the root. Override freely — there is no styling engine to fight.
Contract
The machine-readable schema ships with the package:
import contract from '@lemonadejs/imagelist/contract.json';
verify.json carries the conformance proof produced by verify(Imagelist).
Looking for the v5 plugin? See the archived v5 documentation.