Skip to content

Options & Events

This configurable demo is to quickly explore Justified Gallery settings. Justified Gallery 4.x has no live settings update: when a control changes, the demo destroys the gallery instance and creates a new one with the updated settings, leaving the other settings unchanged.

Events fired by the gallery:



Pass options as the second argument of the constructor:

import { JustifiedGallery } from 'justified-gallery';
import 'justified-gallery/style.css';
const container = document.getElementById('gallery');
const gallery = new JustifiedGallery(container, {
rowHeight: 160,
margins: 4,
});
gallery.init();
Option Default value Description
rowHeight 120 The preferred row height in pixels.
maxRowHeight false Set false to keep it disabled. Can be a number (e.g. 200) which specifies the maximum row height in pixels, or a string which specifies a percentage (e.g. '200%' means that the row height can’t exceed 2 * rowHeight). Values smaller than rowHeight (including 0 and negative numbers) are raised to rowHeight, so they cap the rows at rowHeight instead of disabling the option. Note that this option can crop the images if they need to be taller to be justified.
maxRowsCount 0 Limits the number of rows to show. Justified Gallery hides the unwanted rows, and if the page is resized more (or fewer) images are shown. Note that this option doesn’t limit the number of rows by making images smaller. A value of 0 means disabled.
sizeRangeSuffixes Flickr suffixes (see below) Describes the thumbnail suffix for each size range, so that the library can load the best thumbnail for the displayed size. The default agrees with the Flickr’s suffixes: {100: '_t', 240: '_m', 320: '_n', 500: '', 640: '_z', 1024: '_b'}. Keys can be numbers or strings like 'lt100' (e.g. {512: '_small', 1024: '_big'} uses the '_small' suffix for images that are less than 512px on the longest side, and '_big' for bigger ones). If you only have one thumbnail per image, use a single range with an empty suffix ({0: ''}) to always use the thumbnail provided in the HTML.
thumbnailPath undefined A function to select a custom thumbnail path, for more flexibility than sizeRangeSuffixes. It is called with the current path of the image, the width and the height of the image to show (after it has been resized), and the image element. If this option is defined, sizeRangeSuffixes is not considered.
lastRow 'nojustify' Decide to justify the last row (using 'justify') or not (using 'nojustify'), or to hide the row if it can’t be justified (using 'hide'). With 'nojustify' (or its alias 'left') the last row images are aligned to the left, but they can also be aligned to the center ('center') or to the right ('right').
justifyThreshold 0.9 If 'row width' / 'available space' > justifyThreshold the last row is justified anyway, even when the lastRow setting is 'nojustify', 'left', 'center' or 'right'.
captions true Decide if the library creates the captions (.jg-caption elements) from the alt or title attributes. Captions are hidden by the default stylesheet until they get the jg-caption-visible class, or until you show them with your own CSS (e.g. on hover).
margins 1 The margins between the images, in pixels.
border -1 The border size of the gallery, in pixels. With a negative value the border will be the same as the margins.
waitThumbnailsLoad true If set to false, in presence of width and height attributes on the thumbnails, the layout is built immediately, and the thumbnails appear while they are loaded. See the performance tips.
randomize false Automatically randomize the order of the photos. Ignored when a sort function is set.
filter false Can be false (disabled), a CSS selector string (an entry is kept if it matches the selector), or a function invoked with (entry, index, array) that returns true to keep the entry (as in Array.prototype.filter). The entries that are filtered out get the jg-filtered class, which hides them.
sort false Can be false (don’t sort), or a comparator function (as in Array.prototype.sort).
rtl false Right-to-left mode.
selector 'a' Determines which children of the gallery element are the entries (plain div children are accepted too, except the loading spinner). Note that, for performance reasons, the entries of the gallery are always direct children of the gallery.
imgSelector 'img, a > img, svg, a > svg' Determines, given a gallery entry, how to retrieve the thumbnail.
extension /\.[^.\\/]+$/ The regex used to detect the file extension, needed to reconstruct the thumbnail filenames. Change it if you need; for example /\.jpg$/ detects only the .jpg extension.
refreshTime 200 How often (in milliseconds) the width of the gallery element is checked. If the gallery width has changed, the layout is rebuilt. The check is skipped while the gallery is not visible.
refreshSensitivity 0 Change in the gallery width allowed (in pixels) without rebuilding the layout.
rel null Rewrites the rel attribute of all the entries with the specified value. For example it can be 'gallery1', which some lightboxes use to group images into a gallery.
target null Rewrites the target attribute of all the entries with the specified value. For example, if you don’t use a lightbox, specifying '_blank' opens all the images in a new tab.
triggerEvent () => {} Callback invoked with the event name when the gallery emits an event. It is called with this bound to the JustifiedGallery instance (use a regular function rather than an arrow function to access it).

A few options are easier to understand with an example. You can also try lastRow, maxRowsCount and the other layout options live in the playground at the top of this page.

If your images are served by an image CDN that resizes on the fly (imgix, Cloudinary, Cloudflare Images, a Thumbor server…), let the library build the thumbnail URL from the displayed size instead of using sizeRangeSuffixes. The function receives the image path from the HTML, the width and the height the thumbnail is displayed at (in CSS pixels), and the <img> element:

const gallery = new JustifiedGallery(container, {
thumbnailPath: (currentPath, width, height) => {
// Account for high-density screens, and round up to steps of 100px so
// that resizing the page reuses a few cached URLs.
const size = Math.ceil((width * window.devicePixelRatio) / 100) * 100;
const url = new URL(currentPath, window.location.href);
url.searchParams.set('w', String(size));
return url.href;
},
});
gallery.init();
<a href="https://images.example.com/photo1.jpg">
<img alt="Photo 1" src="https://images.example.com/photo1.jpg?w=300" />
</a>

The src in the HTML is loaded first, to measure the image (unless it has width/height attributes and waitThumbnailsLoad is false), so keep it small. The CDN keeps the aspect ratio, so the width is enough here; use height too if your CDN needs both. The function is called again on every layout, including after a resize.

The last row is often not full. lastRow decides what to do with it:

  • 'nojustify' (default, alias 'left'): left-aligned, not stretched.
  • 'center' / 'right': centered or right-aligned, not stretched.
  • 'justify': stretched to the full width, like the other rows.
  • 'hide': hidden, unless it can be justified.
const gallery = new JustifiedGallery(container, { lastRow: 'center' });
gallery.init();

When the last row is almost full (its width is more than justifyThreshold of the available space, 90% by default), it’s justified anyway, whatever the mode; that’s also when 'hide' keeps it. The images of a non-justified last row get the average height of the other rows, so they don’t look smaller than the rest.

Show only the first rows, for example a preview strip with a “See all” button:

const options = { rowHeight: 140, maxRowsCount: 2 };
let gallery = new JustifiedGallery(container, options);
gallery.init();
document.getElementById('see-all').addEventListener('click', () => {
gallery.destroy();
gallery = new JustifiedGallery(container, { ...options, maxRowsCount: 0 });
gallery.init();
});

The entries of the extra rows stay in the DOM, hidden, and the gallery height covers only the visible rows. Since the rows are rebuilt on resize, a wider gallery shows more images in the same two rows.

For right-to-left pages, rtl: true fills each row from right to left. Pair it with lastRow: 'right', so that an incomplete last row starts from the right as well:

const gallery = new JustifiedGallery(container, {
rtl: true,
lastRow: 'right',
});
gallery.init();

The JustifiedGallery instance returned by the constructor exposes these methods:

Method Description
init() Analyzes all the entries, starts loading the thumbnails, and builds the gallery layout. Call it again after appending new entries at the end of the gallery: the images that have already been loaded and laid out are not processed again, so only the new ones are — useful for the infinite scroll.
updateEntries(norewind) Low-level method, called by init(). Collects the entries from the gallery element and applies sort, randomize and filter to them. With norewind = false the whole entry list is rebuilt; with norewind = true only the entries after the last collected one (matched by selector only) are appended. It doesn’t load images or build the layout by itself.
rewind() Low-level method, used internally when the gallery is resized. Resets the layout state so that the next layout pass starts again from the first entry.
destroy() Destroys the Justified Gallery instance: stops watching the gallery width, removes the inline styles, the jg-* classes and the captions created by the library, restores the original thumbnail src, and fires the jg.destroy event.

There is no live settings update: to change the settings of an existing gallery, call destroy() and create a new instance with the merged settings (this is exactly what the playground above does):

const settings = { rowHeight: 160 };
let gallery = new JustifiedGallery(container, settings);
gallery.init();
function applySettings(changes) {
Object.assign(settings, changes);
gallery.destroy();
gallery = new JustifiedGallery(container, settings);
gallery.init();
}

Events are delivered through the triggerEvent callback option, which receives the event name:

Event Description
jg.complete When the algorithm has finished creating the gallery layout (also after each init() call).
jg.resize When the algorithm has finished rebuilding the layout after the gallery width changed.
jg.rowflush When a new row is ready.
jg.destroy When the gallery instance has been destroyed.
const gallery = new JustifiedGallery(container, {
triggerEvent: (name) => {
if (name === 'jg.complete') {
console.log('layout complete');
}
},
});
gallery.init();

triggerEvent is called with this bound to the JustifiedGallery instance that fired the event. This is handy when the same handler serves several galleries: write it as a regular function, because an arrow function ignores the binding and keeps the this of the surrounding code.

const containers = new Map(); // JustifiedGallery instance -> container element
function onGalleryEvent(name) {
if (name === 'jg.complete') {
// `this` is the instance that completed
containers.get(this).classList.add('is-ready');
}
}
document.querySelectorAll('.gallery').forEach((container) => {
const gallery = new JustifiedGallery(container, { triggerEvent: onGalleryEvent });
containers.set(gallery, container);
gallery.init();
});