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

live
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.

PropTypeDefaultDescription
dataarrayImageListItem[] BY REFERENCE (mutate + touch())
columnsnumber3grid columns (masonry: CSS column count)
gapnumber8px between tiles
rowheightnumber164px per grid row; 0 = natural heights
variantstring''” standard
barbooleanfalseoverlay 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.