# Justified-Gallery for TypeScript and JavaScript Image Layouts

> Justified-Gallery is a TypeScript library that positions image rows across a real HTML container, hides entries until placement, and provides explicit cleanup through destroy(). It fits developers who need justified image layouts in framework-rendered pages or plain browser applications.

**miromannino/Justified-Gallery** — Javascript library to help creating high quality justified galleries of images. Used by thousands of websites as well as the photography community 500px.

- Repository: https://github.com/miromannino/Justified-Gallery
- Website: http://miromannino.github.io/Justified-Gallery/
- Stars: 1,745 · Forks: 294
- Language: TypeScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/miromannino-justified-gallery

## The layout problem Justified-Gallery addresses

Justified-Gallery addresses a specific presentation problem: a page has several images, but fixed columns or equal-size tiles leave unused horizontal space or force the collection into a less useful arrangement. The project describes the result as a justified gallery, similar to the way images are arranged across a brick wall. Its intended users are frontend developers adding photography collections, thumbnails, or image feeds to a website. The README mentions adoption by 500px, but that example establishes usage context rather than proving compatibility with any particular site stack.

The current package is `justified-gallery`, and its primary implementation language is TypeScript. The package publishes one JavaScript entry point and type declarations. It does not require React, Vue, or another UI framework at its API boundary. Instead, it works directly against a real `HTMLElement`. That makes the library relevant to pages built with a framework and to plain JavaScript applications, although the page still needs to provide image elements and image dimensions that the layout process can use.

This is a presentation library, not an image service. The repository does not document fetching images, storing originals, generating thumbnails, editing photographs, or implementing pagination. Although package keywords include `masonry` and `infinite-scroll`, the README does not describe a built-in data loader. Those features would need separate application code if a site requires them.

## The HTMLElement lifecycle used by the TypeScript class

The public usage example constructs `JustifiedGallery` with a DOM container, calls `init()`, and later calls `destroy()`. The class therefore has an explicit lifecycle rather than relying on page unload. `init()` operates after the container is mounted and adds the `justified-gallery` class, which the stylesheet uses to hide entries until they have been positioned. `destroy()` removes that class when the component is unmounted.

The visible architecture is small at the integration boundary: imported JavaScript, imported CSS, a container element, and two lifecycle methods. This is preferable to hiding library behavior behind a framework adapter when the same visual component must work across React, Vue, and plain browser code. The README points to `test/browser/html/react_gallery.tsx` and `test/browser/html/vue_gallery.vue` as examples of those integrations.

The CSS-based hiding behavior is part of the layout sequence, not an optional presentation detail. Without the stylesheet, images may appear before the library has positioned them. With the stylesheet present, direct child anchors, divs, and figures begin at zero opacity and are hidden until positioning occurs. The README abbreviates the example CSS, so it does not establish which properties restore visibility after layout. Adoption should therefore preserve the packaged stylesheet rather than copying only the partial selector shown in the documentation.

## Stylesheet loading and the first initialized gallery

The README does not provide a dedicated downstream installation command for adding the package to an application. It does identify the npm package as `justified-gallery`, and the documented usage imports both its class and stylesheet. A bundler-based page can follow the complete initialization example after installing that package according to the surrounding application's package manager setup. The important ordering constraint is that the CSS must load before the gallery script runs.

The shortest documented first use is below. The container should already be mounted when `init()` is called. The imported stylesheet makes the library's hiding rules available and `destroy()` defines cleanup behavior for a later unmount.

```ts
import { JustifiedGallery } from "justified-gallery";
import "justified-gallery/style.css";

const gallery = document.getElementById("gallery");
const jg = new JustifiedGallery(gallery);
jg.init();

// later, on unmount:
jg.destroy();
```

The README does not show the image markup needed for a complete page, its layout options, or its dynamic entry API. Consequently, the initialization example alone does not document how to populate, resize, or append entries after `init()`. Those details should be checked in the project API documentation or type declarations before treating this snippet as a full gallery implementation.

## Preventing raw images before JavaScript initialization

Justified-Gallery includes a deliberate protection against a visible layout flash, but the protection has a timing boundary. `init()` adds the `justified-gallery` class only when JavaScript executes. If the class is absent before that point, the stylesheet cannot hide direct child entries. A server-rendered page can therefore show raw, unpositioned images before the script initializes the gallery.

The README addresses this by recommending that the class be added directly in the markup. The example is short because the omitted content represents gallery entries rather than a complete runnable document.

```html
<div id="gallery" class="justified-gallery">...</div>
```

When the script runs, adding the class again is harmless, and `destroy()` removes it during cleanup. This behavior matters for framework pages that render their image containers before client-side JavaScript is ready. It also exposes a real integration constraint: a stylesheet imported only by JavaScript may not prevent server-rendered content from appearing first. Pages that require hidden entries from the initial response must include `class="justified-gallery"` in the container markup.

For a plain script or CDN setup without a build step, the README says to link the distribution stylesheet in `<head>` before the script tag. It gives this form:

```html
<link
  rel="stylesheet"
  href="https://.../justified-gallery/dist/assets/justified-gallery.css"
/>
```

The ellipsis is deliberate in the documentation. It is a placeholder for the host location rather than a deployable URL, so an adopter must obtain the actual published asset location before copying the tag.

## Package distribution, browser assets, and supported runtimes

The npm package uses ESM metadata and exposes a stylesheet through a dedicated export. Its main and module fields point to `dist/justified-gallery.js`, its types field points to `dist/justified-gallery.d.ts`, and the `./style.css` export points to `dist/assets/justified-gallery.css`. Only the `dist` directory is included in the published package. This packaging makes the runtime bundle and stylesheet available through explicit import paths, including for projects using TypeScript type checking.

The build is documented through repository scripts rather than consumer setup. `npm run build` runs Vite and then TypeScript declaration generation. Vite bundles `src/justified-gallery.ts` into the distribution JavaScript and CSS, while `tsc -p tsconfig.build.json` emits declarations. `npm run preview` serves the built output for local inspection.

```bash
npm install
npm run dev
npm run build
npm run preview
npm test
```

These are contributor and repository commands rather than commands for embedding the library in an unrelated site. The README identifies Node.js as a prerequisite and `package.json` declares support for `^20.19.0 || >=22.12.0`. That declaration is especially relevant to development and release environments. It does not, by itself, identify which browsers are supported, and the README does not document a browser support matrix.

The repository also documents `npm run test:unit`, `npm run test:e2e`, and `scripts/test-local-package.sh`. The unit command uses Vitest, the browser command uses Playwright, and the local package script builds, links, and serves the package through a sandbox consumer. These documented paths indicate a testing structure, but they do not substitute for checking an application's own content, framework lifecycle, and build pipeline.

## Maintenance, licensing, and the cost of integration

The repository is not archived, its last push was on 2026-10-16, and version 4.0.2 was released on 2026-09-13. Those facts indicate recent project activity, but they do not establish that every framework integration or browser configuration is supported. The default branch is `master`, and the package is published under the MIT license. The license permits use, modification, distribution, and private use subject to its conditions. Projects still need to retain the required copyright and license notice when redistributing the software or substantial portions of it.

Upgrade cost appears concentrated in packaging and browser integration rather than a documented framework migration API. Version 4 exposes an ESM import, a class-based lifecycle, a separate CSS export, and TypeScript declarations. Applications that previously depended on an undocumented legacy entry path may need to review imports and package resolution. The README does not provide a migration guide, so it cannot establish the exact changes required by existing users.

The most concrete maintenance obligations come from lifecycle correctness. A site must call `init()` once the container exists and call `destroy()` when removing the gallery. Leaving the instance alive after its host element disappears can retain application behavior, while failing to call `init()` after a framework remount means the new container has not been initialized by documented code. Initial markup must also carry the class if hiding entries before JavaScript matters.

Compared with a native CSS masonry arrangement, Justified-Gallery takes a JavaScript-controlled positioning approach and adds a stylesheet, DOM lifecycle, and package dependency. A CSS-only approach can be simpler when the browser's native layout support and target visual order already meet the site's requirements. For a justified result tied to explicit `init()` and `destroy()` behavior, the package offers a defined integration model, but the README does not document sizing options, accessibility behavior, image-loading events, or resize callbacks. Those are the first API details to verify for a production integration.

## Conclusion

Justified-Gallery is appropriate for developers building image collections whose rows should fill the available width without requiring framework-specific components. It is less suitable for a gallery whose priority is a fixed grid, uniform item size, or a fully server-rendered presentation. Before adopting it, verify the page contains a mounted HTMLElement with suitable entries, load justified-gallery/style.css before initialization, and confirm that calling destroy() removes the behavior when the surrounding UI is removed. Its MIT license permits reuse under the license terms, while adoption still requires checking the package's supported Node.js versions, 4.0.2 release, ESM entry points, and compatibility with the site's build system.

## FAQ

### How do I initialize Justified-Gallery in a TypeScript application?

Import `JustifiedGallery` and `justified-gallery/style.css`, pass the mounted `HTMLElement` to the constructor, and call `jg.init()`. Call `jg.destroy()` when the gallery is unmounted.

### Why are Justified-Gallery images hidden before initialization?

The stylesheet targets children of a container with the `justified-gallery` class and hides them until they are positioned. To apply that behavior before JavaScript runs, add the class directly to the container markup.

### Which Node.js versions are declared for Justified-Gallery development?

The package declares `^20.19.0 || >=22.12.0` in its `engines` field. The README separately lists Node.js and `npm install` as development prerequisites.

## Sources

- [License: MIT](https://github.com/miromannino/Justified-Gallery/blob/master/LICENSE)
- [miromannino/Justified-Gallery on GitHub](https://github.com/miromannino/Justified-Gallery)
- [Project website](http://miromannino.github.io/Justified-Gallery/)
- [README](https://github.com/miromannino/Justified-Gallery/blob/master/README.md)
- [Releases](https://github.com/miromannino/Justified-Gallery/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/miromannino-justified-gallery
