Open-source project
feimosi/baguetteBox.js avatar
feimosi/baguetteBox.js

baguetteBox.js: a 3.2KB vanilla JavaScript lightbox for image galleries

:zap: Simple and easy to use lightbox script written in pure JavaScript

2,503 stars426 forksJavaScriptMIT

At a glance

What is it?
baguetteBox.js is a dependency-free lightbox script that turns a list of anchor tags into a swipeable, captioned gallery. It is small, MIT-licensed, and deliberately narrow in scope.
Who is it for?
Adopt baguetteBox.js if you need a small, dependency-free lightbox over plain anchor tags and you are willing to drive it from JavaScript yourself. Do not adopt it if you need a gallery that builds its own markup, lazy-loads from a data source, or works without JavaScript.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem baguetteBox.js solves, and who it is for

Most lightbox libraries arrive with a framework attached. baguetteBox.js takes the opposite position: it expects you to have already written the gallery markup as a container of anchor tags, each anchor pointing at a full-size image and wrapping a thumbnail. The script's job is to intercept clicks on those anchors and present the full image in an overlay. The README describes it as a "Simple and easy to use lightbox script written in pure JavaScript", and the feature list backs that up: no dependencies, multiple galleries with per-gallery options, swipe gestures, full-screen mode, captions, CSS3 transitions, SVG buttons, and a size of around 3.2KB gzipped.

The audience is narrow on purpose. If you are building a static site, a documentation page, a portfolio, or a server-rendered template where the images already exist as HTML, baguetteBox.js fits without a build step. If you are building a single-page application that fetches image lists at runtime and renders them from state, you will be writing the markup generation yourself anyway, and the value of the library drops to the overlay behaviour alone.

How the run() call wires anchors into an overlay

The mechanism is selector-driven. You call baguetteBox.run() with a CSS selector; the README states the first argument is a selector to a gallery or galleries containing a tags. The API section documents the return value as an array of gallery objects reflecting the elements found by the selector, which tells you the library walks the matched containers and builds an internal gallery array per container rather than treating the page as one global gallery. That is what makes multiple-gallery support with custom options possible.

Which anchors qualify is decided by the filter option, a RegExp applied to the a.href attribute. Its documented default is /.+\.(gif|jpe?g|png|webp)/i, so an anchor pointing at a .jpg, .jpeg, .png, .gif or .webp file is picked up and anything else is skipped. This is the single most important detail to internalise: if your image URLs carry query strings, a CDN transform path, or an extension the pattern does not match, the anchor silently will not open. You can override the pattern, but the default is doing real filtering work, not decoration.

Captions come from a title or data-caption attribute on the anchor, per the usage section. The captions option accepts either a Boolean or a function receiving the a element and returning a string, which is the escape hatch when the caption text has to be computed rather than written into the markup. Around that, the options table exposes preload (a Number, default 2) for how many files to preload, animation as 'slideIn', 'fadeIn' or false, and afterShow, afterHide and onChange callbacks for hooking the overlay into your own code.

Installing baguetteBox.js and opening a first gallery

The README lists npm, Yarn, Bower, CDN, manual download from the dist folder, and Composer as installation routes. The npm package name is baguettebox.js, and the package.json points main at dist/baguetteBox.min.js and style at dist/baguetteBox.min.css, so a bundler will resolve the JavaScript entry from the package name.

Install it from npm:

bash
npm install baguettebox.js --save

Then import the script and the stylesheet. The README gives both the CommonJS and ES2015 forms; the ES2015 form is:

js
import baguetteBox from 'baguettebox.js';

The stylesheet ships inside the package and the README shows importing it from the dist path:

scss
@import 'baguettebox.js/dist/baguetteBox.min.css';

With both in place, write the gallery markup. Each anchor points at the full-size image and wraps the thumbnail, and the caption goes on the anchor as data-caption:

html
<div class="gallery">
    <a href="img/2-1.jpg" data-caption="Image caption">
        <img src="img/thumbnails/2-1.jpg" alt="First image">
    </a>
    <a href="img/2-2.jpg">
        <img src="img/thumbnails/2-2.jpg" alt="Second image">
    </a>
</div>

Finally initialize against that container. baguetteBox.run('.gallery') returns an array of gallery objects, one per matched container:

js
baguetteBox.run('.gallery');

If you loaded the file with a plain script tag instead of a module, the README notes that baguetteBox is on the global scope and that you must run it after the document has loaded:

html
<script>
window.addEventListener('load', function() {
  baguetteBox.run('.gallery');
});
</script>

What you should see after this is a click on any thumbnail opening the full-size image in an overlay, with the caption from data-caption beneath it. If nothing opens, check the filter regex against your actual href values before changing anything else.

Where baguetteBox.js stops being the right tool

The library has no data layer. It reads anchors that already exist in the DOM. If your gallery is populated after a fetch, you have to render the anchors first and then call run() against the container, and the README does not document a re-scan or refresh API for a container whose contents changed after initialization. The API section covers run(), show() and the options table; there is no documented method for adding images to an existing gallery object. That is a real constraint for infinite-scroll galleries and for any interface where the image set is a moving target.

The second limitation is the filter. Because the default pattern matches on file extension in the href, image URLs that do not end in a recognised extension will be ignored unless you supply your own RegExp. The README does not document what happens to anchors that fail the filter beyond the implication that they are not treated as gallery items.

Third, this is a JavaScript-dependent overlay. Nothing in the README describes a no-JavaScript fallback, so the anchor's href remains the only behaviour if the script does not load. That is actually a reasonable degradation, since the anchor still points at the image, but it means the lightbox is an enhancement, not a guarantee. Accessibility is listed as a feature, and the buttons option defaults to 'auto', which hides buttons on touch-enabled devices or when only one image is available; the README does not go further into keyboard handling, so verify that yourself if keyboard navigation is a requirement.

How baguetteBox.js differs from a full gallery framework

The obvious comparison is with a lightbox that is part of a larger gallery component, such as PhotoSwipe or the lightbox bundled into a UI kit. The difference is where the markup lives. baguetteBox.js takes your existing anchors as input and adds behaviour on top; a gallery framework typically owns the markup as well, generating the thumbnail grid and the overlay from a configuration or a data array. If you want the component to build the grid for you, baguetteBox.js is the wrong shape and you will end up writing the grid yourself.

The second difference is dependency policy. baguetteBox.js ships with no runtime dependencies, which is why the size claim of around 3.2KB gzipped is plausible for the whole thing including styles. A framework-based alternative brings its own runtime assumptions and its own CSS, and you inherit both. The trade is capability: baguetteBox.js gives you an overlay, captions, swipe, full-screen and preloading, and stops there. There is no zoom, no video, no thumbnail strip, and no documented plugin surface. Choose based on whether your needs end where its feature list ends.

Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-03-09. The most recent release is v1.13.0 from 2025-11-09, following v1.12.0 in 2024-07-14 and v1.11.1 in 2020-03-31. That release spacing is worth reading carefully: there was a gap of more than four years between v1.11.1 and v1.12.0, then two releases within roughly sixteen months. The project moves in bursts rather than on a schedule, so pin a version and treat upgrades as deliberate events rather than routine pulls.

On the build side, package.json shows a gulp 3.9.1 pipeline with gulp-sass, gulp-uglify and gulp-usemin, plus a postinstall script that runs npm rebuild node-sass. A contributor working on the source will meet that toolchain; a consumer installing the package only needs dist/baguetteBox.min.js and dist/baguetteBox.min.css, which are the files published in the files array alongside src. The runtime footprint for a consumer is therefore two static assets and no dependency tree.

The licence is MIT, stated in package.json and shown by the badge in the README. MIT permits use, modification and redistribution provided the copyright notice and permission notice are retained; the practical implication is that you can bundle the minified files into a commercial product. This is a description of the licence text, not legal advice, and if your organisation has specific obligations around attribution you should have someone check the LICENSE file in the repository.

Editorial conclusion

Adopt baguetteBox.js if you need a small, dependency-free lightbox over plain anchor tags and you are willing to drive it from JavaScript yourself. Do not adopt it if you need a gallery that builds its own markup, lazy-loads from a data source, or works without JavaScript. Before committing, verify that your anchors point at real image files matching the default filter regex, and check whether the image extensions you serve are covered by it.

Frequently asked questions

How do I install baguetteBox.js with npm?

Run npm install baguettebox.js --save. The package.json entry points main at dist/baguetteBox.min.js and style at dist/baguetteBox.min.css, so both the script and the stylesheet resolve from the package name.

Why does an image not open in the baguetteBox.js lightbox?

The filter option decides which anchors count, and its default is /.+\.(gif|jpe?g|png|webp)/i applied to the a.href attribute. An href that does not match that pattern, for example one with a different extension, will not be treated as a gallery item unless you pass your own RegExp.

How do I add captions to images in baguetteBox.js?

Put a title or data-caption attribute on the a tag, as shown in the README usage example. The captions option defaults to true, and passing a function instead uses the string it returns, with the a element as the only argument.

Official sources

  1. feimosi/baguetteBox.js on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/feimosi-baguettebox-js.svg)](https://hysenlabs.com/projects/feimosi-baguettebox-js)