Demos

React image gallery component

@lightgallery/react is a native React image gallery: React renders every node, there is no wrapper around the vanilla library, and it works in Next.js out of the box. Pinch and double-tap zoom, animated thumbnails, captions, rotate, fullscreen and sharing all come as tree-shakable plugins. The full component API is in the React package docs.

Demo

The gallery below is an actual @lightgallery/react component, every node in the grid and in the lightbox is rendered by React.

man sitting on wall with artwork and lamppaintings on a wallblue yellow red and pink balloonscolorful umbrellas hanging over a narrow alleya bicycle by a colorful graffiti wallman walking on road during daytimea street with flags hanginga yellow car next to tall buildingspeople walking under umbrellasa white building with multicolored windowsa book store with lots of booksa man walking next to tall buildingscolorful houses with graffiti on a city street
Install
npm install @lightgallery/react lightgallery

The React package ships no CSS, the stylesheets come from the lightgallery package and are shared by every binding:

import 'lightgallery/css/lightgallery.css';
import 'lightgallery/css/lg-thumbnail.css';
import 'lightgallery/css/lg-zoom.css';
Thumbnail grid

Wrap your trigger markup in <LightGalleryItem>. Mount order is slide order, the triggers server-render as plain markup (so the grid stays crawlable), and clicking one opens the lightbox on that slide.

import { LightGallery, LightGalleryItem } from '@lightgallery/react';
import Thumbnail from '@lightgallery/react/plugins/thumbnail';
import Zoom from '@lightgallery/react/plugins/zoom';

const items = [
    {
        src: 'img/1-1600.jpg',
        thumb: 'img/1-240.jpg',
        alt: 'Mountains',
        // enables the zoom-from-origin open animation
        lgSize: '1600-1067',
        caption: <h4>Mountains</h4>,
    },
    {
        src: 'img/2-1600.jpg',
        thumb: 'img/2-240.jpg',
        alt: 'Forest path',
        lgSize: '1600-2400',
        caption: <h4>Forest path</h4>,
    },
];

export function Gallery() {
    return (
        <LightGallery plugins={[Thumbnail, Zoom]} zoom={{ scale: 1.5 }}>
            {items.map((item) => (
                <LightGalleryItem key={item.src} item={item} href={item.src}>
                    <img src={item.thumb} alt={item.alt} />
                </LightGalleryItem>
            ))}
        </LightGallery>
    );
}
Settings and plugins are props

Core settings are flat props with the same names as the vanilla library (mode, speed, loop, preload, download, …). Each plugin contributes one settings prop named after it, typed through the plugin’s own entry point:

<LightGallery
    plugins={[Thumbnail, Zoom]}
    speed={400}
    thumbnail={{ animateThumb: true, thumbWidth: 130 }}
    zoom={{ scale: 1.5, actualSize: true }}
/>

Enabling a plugin is the plugins array, a bare thumbnail boolean prop does nothing on its own.

Controlled mode

Own the open state and the index yourself when the gallery is opened from your own UI rather than from a trigger grid. The slides prop replaces the trigger children:

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

<>
    <button onClick={() => setOpen(true)}>Open gallery</button>
    <LightGallery
        slides={items}
        plugins={[Thumbnail, Zoom]}
        open={open}
        onClose={() => setOpen(false)}
        index={index}
        onIndexChange={setIndex}
    />
</>;
TypeScript

The package is written in TypeScript and ships its own types, GalleryItem for slide data, LightGalleryRefHandle for the imperative handle:

import { useRef } from 'react';
import { LightGallery } from '@lightgallery/react';
import type { GalleryItem, LightGalleryRefHandle } from '@lightgallery/react';

const items: GalleryItem[] = [
    { src: 'img/1-1600.jpg', thumb: 'img/1-240.jpg', alt: 'Mountains' },
];

const gallery = useRef<LightGalleryRefHandle>(null);

<>
    <button onClick={() => gallery.current?.openGallery(0)}>Open</button>
    <LightGallery ref={gallery} slides={items} />
</>;

The handle covers openGallery(index?), closeGallery(), goToSlide(i), nextSlide(), prevSlide() and refresh(). Lifecycle events are callback props with the documented names, onBeforeSlide, onAfterSlide, onSlideItemLoad, and the rest.

Next.js and SSR

Every entry point imports cleanly in bare Node, and the lightbox portal mounts after hydration, so no dynamic(() => …, { ssr: false }) wrapper is needed. With the App Router, put the gallery in a client component and import the CSS from your root layout:

'use client';

import { LightGallery, LightGalleryItem } from '@lightgallery/react';

The Next.js image gallery demo builds a complete App Router page with next/image thumbnails.

More in the React package docs, SSR notes, the full prop surface and the accessibility behavior. See also the React video gallery and React carousel demos.

Edit this page on GitHub