Responsive Flickr-Style Photo Grid in Vanilla JS – Justified Gallery

Category: Javascript , Layout | September 15, 2026
Authormiromannino
Last UpdateSeptember 15, 2026
LicenseMIT
Views0 views
Responsive Flickr-Style Photo Grid in Vanilla JS – Justified Gallery

Justified Gallery is a dependency-free JavaScript library that arranges mixed-aspect-ratio images into responsive justified rows.

Each row adapts to the available gallery width, with configurable height, spacing, and behavior for an incomplete final row.

Version 4 uses an ES module class API and no longer requires jQuery. The legacy Justified Gallery page on jQueryScript retains the jQuery 3.8.1 setup for older projects.

Features

  • Responsive justified rows for portrait, landscape, and square images.
  • Configurable row height, maximum row height, spacing, and gallery border.
  • 6 modes for handling an incomplete final row.
  • Automatic captions from image alternative text or entry titles.
  • CSS selector and function-based filtering.
  • Custom sorting or randomized entry order.
  • Right-to-left gallery layouts.
  • Maximum row count for compact gallery previews.
  • Automatic layout recalculation after container width changes.

How To Use It

Installation

Install the package through npm:

npm install justified-gallery

Import the JavaScript class and stylesheet:

import { JustifiedGallery } from 'justified-gallery';
import 'justified-gallery/style.css';

Basic Usage

The default gallery entry selector is a. Each entry normally contains an image or SVG.

Keep the justified-gallery class in the initial markup when the stylesheet loads before JavaScript. This keeps unfinished entries hidden until their calculated positions are ready.

<div id="gallery" class="justified-gallery">
  <a href="images/mountain-large.jpg" title="Mountain lake">
    <img
      src="images/mountain-thumb.jpg"
      alt="Mountain lake at sunrise"
    >
  </a>
  <a href="images/coast-large.jpg" title="Rocky coast">
    <img
      src="images/coast-thumb.jpg"
      alt="Rocky coast beside the ocean"
    >
  </a>
  <a href="images/forest-large.jpg" title="Forest trail">
    <img
      src="images/forest-thumb.jpg"
      alt="Trail through a pine forest"
    >
  </a>
  <a href="images/city-large.jpg" title="City skyline">
    <img
      src="images/city-thumb.jpg"
      alt="City skyline after sunset"
    >
  </a>
</div>

The default thumbnail system expects filename variants such as _m, _z, and _b. Keep conventional image URLs unchanged with thumbnailPath when your files do not follow that suffix scheme.

const galleryElement = document.getElementById('gallery');
const gallery = new JustifiedGallery(galleryElement, {
  rowHeight: 180,
  margins: 8,
  lastRow: 'nojustify',
  thumbnailPath: function(currentPath) {
    return currentPath;
  }
});
gallery.init();

Load It Directly From A CDN

Load its stylesheet in the document head:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/[email protected]/dist/assets/justified-gallery.css"
>

Import the JavaScript file from a module script:

<script type="module">
  import { JustifiedGallery } from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/justified-gallery.js';
  const galleryElement = document.getElementById('gallery');
  const gallery = new JustifiedGallery(galleryElement, {
    rowHeight: 180,
    margins: 8,
    thumbnailPath: function(currentPath) {
      return currentPath;
    }
  });
  gallery.init();
</script>

Configuration Options

  • sizeRangeSuffixes (object): Maps image dimensions to filename suffixes. Default: {100: '_t', 240: '_m', 320: '_n', 500: '', 640: '_z', 1024: '_b'}.
  • thumbnailPath (function | undefined): Creates the thumbnail URL from the existing URL, calculated width, calculated height, and image element. It takes priority over sizeRangeSuffixes. Default: undefined.
  • rowHeight (number): Preferred row height in pixels. Default: 120.
  • maxRowHeight (number | string | false): Caps row height in pixels or as a percentage of rowHeight, such as '150%'. Default: false.
  • maxRowsCount (number): Maximum number of displayed rows. 0 disables the limit. Default: 0.
  • margins (number): Space between gallery entries in pixels. Default: 1.
  • border (number): Outer gallery border in pixels. A negative value uses the margin value. 0 removes the border. Default: -1.
  • lastRow (string): Controls an incomplete final row. Accepted values are 'justify', 'nojustify', 'left', 'center', 'right', and 'hide'. Default: 'nojustify'.
  • justifyThreshold (number): Ratio between 0 and 1 that determines when an incomplete row is justified despite the selected last-row mode. Default: 0.9.
  • waitThumbnailsLoad (boolean): Waits for thumbnail dimensions before calculating the layout. Default: true.
  • captions (boolean): Enables image captions. The image alt attribute is checked first, followed by the entry title attribute. Default: true.
  • rel (string | null): Sets the rel attribute on analyzed gallery entries. Default: null.
  • target (string | null): Sets the target attribute on analyzed gallery entries. Default: null.
  • extension (RegExp): Matches the file extension used during automatic thumbnail URL rewriting. Default: /\.[^.\\/]+$/.
  • refreshTime (number): Interval in milliseconds between gallery width checks. Default: 200.
  • refreshSensitivity (number): Minimum width change in pixels before the gallery recalculates its layout. Default: 0.
  • randomize (boolean): Randomizes gallery entry order before layout. A custom sort function takes precedence. Default: false.
  • rtl (boolean): Reverses row direction for right-to-left layouts. Default: false.
  • sort (function | false): Comparator function for sorting gallery entries before layout. Default: false.
  • filter (string | function | false): Limits displayed entries with a CSS selector or filter function. Default: false.
  • selector (string): CSS selector used for gallery entries. Default: 'a'.
  • imgSelector (string): Selector used to find an image or SVG inside each entry. Default: 'img, a > img, svg, a > svg'.
  • triggerEvent (function): Receives lifecycle event names during layout, resize, completion, and destruction. The default function performs no action.

Last Row Alignment

lastRow controls the position and sizing of entries when the final row does not fill the available width.

const gallery = new JustifiedGallery(
  document.getElementById('gallery'),
  {
    rowHeight: 160,
    margins: 6,
    lastRow: 'center'
  }
);
gallery.init();

Available modes:

justify
nojustify
left
center
right
hide

Image Captions

Captions are enabled by default. Justified Gallery checks the image alt text first and falls back to the entry title.

<div id="gallery" class="justified-gallery">
  <a href="large/photo-1.jpg" title="Alternative caption">
    <img
      src="thumb/photo-1.jpg"
      alt="Cabin beside a frozen lake"
    >
  </a>
</div>

Disable captions during initialization when the gallery should contain images only:

const gallery = new JustifiedGallery(
  document.getElementById('gallery'),
  {
    captions: false
  }
);
gallery.init();

Sorting, Filtering, And Random Order

sort accepts a comparison function that receives gallery entry elements.

const gallery = new JustifiedGallery(
  document.getElementById('gallery'),
  {
    sort: function(a, b) {
      return Number(a.dataset.order) - Number(b.dataset.order);
    }
  }
);
gallery.init();

A string passed to filter works as a CSS selector:

<div id="gallery" class="justified-gallery">
  <a class="featured" href="large/1.jpg">
    <img src="thumb/1.jpg" alt="Mountain">
  </a>
  <a href="large/2.jpg">
    <img src="thumb/2.jpg" alt="Beach">
  </a>
  <a class="featured" href="large/3.jpg">
    <img src="thumb/3.jpg" alt="Forest">
  </a>
</div>
const gallery = new JustifiedGallery(
  document.getElementById('gallery'),
  {
    filter: '.featured'
  }
);
gallery.init();

Custom Thumbnail URLs

thumbnailPath receives the original image URL, calculated display width, calculated display height, and image element. Image CDN URLs can use the calculated dimensions directly.

const gallery = new JustifiedGallery(
  document.getElementById('gallery'),
  {
    thumbnailPath: function(currentPath, width, height) {
      const url = new URL(currentPath, window.location.href);
      url.searchParams.set('w', Math.ceil(width));
      url.searchParams.set('h', Math.ceil(height));
      return url.toString();
    }
  }
);
gallery.init();

Lifecycle API

Create an instance with a gallery element and an optional settings object:

const gallery = new JustifiedGallery(element, options);

Initialize image analysis, row layout, captions, and width monitoring:

gallery.init();

Remove the gallery instance and its generated layout state:

gallery.destroy();

Lifecycle Callback

triggerEvent receives a lifecycle event name.

const gallery = new JustifiedGallery(
  document.getElementById('gallery'),
  {
    triggerEvent: function(name) {
      if (name === 'jg.complete') {
        console.log('Gallery layout complete');
      }
      if (name === 'jg.resize') {
        console.log('Gallery layout recalculated');
      }
    }
  }
);
gallery.init();

Available values:

  • jg.rowflush: A completed row has been positioned.
  • jg.resize: The gallery has been rebuilt after a width change.
  • jg.complete: The initial gallery layout has finished.
  • jg.destroy: The instance has been destroyed.

Alternatives

You Might Be Interested In:


Leave a Reply