liftbox

Migrating from lightGallery

An MIT-licensed lightGallery alternative for React. Map @lightgallery/react props and plugins to liftbox and drop the commercial license.

lightGallery 3 ships under GPL-3.0 or a commercial license you pay for, so a closed-source project has to buy one. This package is MIT: free for any project, commercial or not, and there is no license key to set.

The React APIs are close. Both have a controlled mode with slides, open, index, onIndexChange and onClose, so most of a migration is renaming. This guide maps @lightgallery/react 3.0. See the comparison for how the two differ overall.

What has no equivalent

Check this list first. If your gallery depends on one of these, this package is not a drop-in replacement:

  • Wistia videos.
  • The comment, medium zoom, relative caption and Vimeo thumbnail plugins.
  • Inline galleries rendered inside the page with container. Here container only picks where the portal mounts.
  • Facebook, X and Pinterest share buttons. Sharing goes through the system share sheet, with a copy-link fallback.
  • Transitions other than slide, fade and zoom.

Install and imports

- npm install @lightgallery/react lightgallery
+ npm install @esdrassantos06/gallery
- import { LightGallery } from "@lightgallery/react";
- import Thumbnail from "@lightgallery/react/plugins/thumbnail";
- import Zoom from "@lightgallery/react/plugins/zoom";
- import "lightgallery/css/lightgallery.css";
- import "lightgallery/css/lg-thumbnail.css";
- import "lightgallery/css/lg-zoom.css";
+ import { Lightbox } from "@esdrassantos06/gallery";
+ import "@esdrassantos06/gallery/styles.css";

There are no plugins to import and one stylesheet. Thumbnails, zoom and fullscreen are on by default. Video, YouTube and Vimeo work without setup.

Controlled galleries

- const [open, setOpen] = useState(false);
- const [index, setIndex] = useState(0);
+ const [index, setIndex] = useState(-1);

- <LightGallery
-   plugins={[Thumbnail, Zoom]}
-   slides={items}
-   open={open}
-   onClose={() => setOpen(false)}
-   index={index}
-   onIndexChange={setIndex}
- />
+ <Lightbox
+   slides={slides}
+   open={index >= 0}
+   index={Math.max(index, 0)}
+   onIndexChange={setIndex}
+   onClose={() => setIndex(-1)}
+ />

One index of -1 for "closed" is the usual pattern here, but a separate open state works too. Keep Lightbox mounted so the close animation can play.

Thumbnail triggers

There is no LightGalleryItem. Render your own buttons and pass getThumbnail, which lightGallery does through lgSize and zoomFromOrigin. It makes the image fly out of the clicked thumbnail, cropped the same way, and returns focus to it on close.

const thumbnails = useRef<(HTMLButtonElement | null)[]>([]);

{
  slides.map((slide, i) => (
    <button
      key={slide.src}
      ref={(el) => {
        thumbnails.current[i] = el;
      }}
      onClick={() => setIndex(i)}
      aria-label={`Open ${slide.alt}`}
    >
      <img src={slide.thumbnail} alt="" />
    </button>
  ));
}

<Lightbox
  // ...
  getThumbnail={(i) => thumbnails.current[i]}
/>;

Or use one of the grids, which do this for you.

Items to slides

lightGalleryThis package
srcsrc
thumbthumbnail
altalt
lgSize: "1600-1067"width: 1600, height: 1067
srcset, sizessrcSet, sizes
sources (<picture>)sources, with srcSet in place of srcset
titletitle
caption, captionHtmldescription, which takes any React node. No HTML strings.
posterposter
iframe: truetype: "iframe"
downloadUrldownload, a URL or false
download (a filename)downloadName
slideNamenames in useLightboxHash
shareUrlshare={{ url: (slide, index) => ... }} on the lightbox

A YouTube or Vimeo link in src becomes an embed, as it does with lightGallery's video plugin. Self-hosted video files are detected from the extension, or set type: "video", and take sources and tracks. See Slides.

Settings

lightGalleryThis package
slides, open, indexslides, open, index
onIndexChange, onCloseonIndexChange, onClose
onAfterOpen, onAfterCloseonAfterOpen, onAfterClose
modetransition: "slide", "fade" or "zoom"
speed, easing--eg-duration, --eg-easing
looploop
preloadpreload
closeOnTapcloseOnBackdropClick
swipeToCloseBuilt in. swipe={false} turns it off with sideways swipes.
escKey, keyPresskeyboard
trapFocusAlways on
downloaddownload
toolbarOverflowtoolbarOverflow
hideBarsDelayidle, in milliseconds
directiondir
captionPositioncaptionPosition: "bar" or "slide"
containercontainer
stringslabels, with different keys. See Labels.
render.caption, render.counterrender.caption, render.counter
render.iconicons. See Icons.
render.prevButton, render.nextButtonNot replaceable. Restyle through classNames.arrow and --eg-arrow-* variables.
classNameclassName, and classNames for each part
licenseKeyDelete it

Plugins

lightGallery pluginThis package
ThumbnailBuilt in. thumbnails={false} to hide it.
ZoomBuilt in. zoom={{ maxScale, step, doubleTapScale, wheel }}. lightGallery's scale is step.
VideoBuilt in. Embeds exist only on the current slide, and neighbors show their poster.
Autoplayslideshow={{ interval, autoplay, progress }}, from slideShowInterval, slideShowAutoplay and progressBar.
FullscreenBuilt in. fullscreen={false} to hide it.
HashuseLightboxHash
Pagerpager
Shareshare
Rotaterotate, and flip for the flip buttons
Origin cropBuilt in with getThumbnail
JustifiedJustifiedGrid, next to MasonryGrid and UniformGrid

Justified grid

- <LightGallery plugins={[Thumbnail, Zoom]}>
-   <JustifiedGrid rowHeight={180} gap={8}>
-     {items.map((item) => (
-       <LightGalleryItem key={item.src} item={item} data-lg-size={item.lgSize}>
-         <img src={item.thumb} alt={item.alt} />
-       </LightGalleryItem>
-     ))}
-   </JustifiedGrid>
- </LightGallery>
+ <JustifiedGrid ref={grid} slides={slides} onOpen={setIndex} rowHeight={180} gap={8} />
+ <Lightbox
+   slides={slides}
+   open={index >= 0}
+   index={Math.max(index, 0)}
+   onIndexChange={setIndex}
+   onClose={() => setIndex(-1)}
+   getThumbnail={(i) => grid.current?.getThumbnail(i)}
+ />

The grid reads width and height from each slide, so there is no data-lg-size. grid is a useRef<GridHandle>(null).

Styling

The lightgallery/css/* files are replaced by one stylesheet and --eg-* CSS variables. The common ones:

GoalThis package
Backdrop color--eg-background
Text and icons--eg-color
Animation length--eg-duration
Stacking--eg-z-index

The full list is in Styling.

Edit this page on GitHub

On this page