Skip to content
Template Empire
Browse components

Gallery Lightbox Modal

A free React image lightbox modal with a native focus trap, keyboard navigation, captions and a thumbnail rail.

Customise

0.78
0.32s
20px

Code

<ModalLightboxGallery
  images={[
    {
      id: "held-light",
      src: "/held-light.jpg",
      alt: "Abstract sun study in warm gradient tones",
      caption: "Held Light No. 4",
      width: 1600,
      height: 1000,
    },
    {
      id: "quiet-horizon",
      src: "/quiet-horizon.jpg",
      alt: "Minimal horizon line dividing two cool gradient tones",
      caption: "Quiet Horizon",
      width: 1600,
      height: 900,
    },
    // ...two to twelve images total
  ]}
/>

Gallery Lightbox Modal is a free React image lightbox for Next.js, built with Motion and Tailwind on top of the native dialog element. It renders its own grid of thumbnail buttons; activating one opens the lightbox at that exact image with a labelled dialog, a full focus trap and Escape to close, and closing returns focus to the exact thumbnail that opened it.

Previous and Next buttons, the arrow keys, and Home and End move cyclically through the collection, while a second thumbnail rail inside the dialog mirrors the same selection and scrolls its active item into view. A crossfade, scale or bounded slide plays between images inside a fixed-height stage, so switching images never shifts the surrounding layout, and only the two neighbouring images are preloaded once the lightbox opens. Every image carries meaningful alt text or an explicit decorative marking, an optional caption renders in a figcaption tied to the active figure, and with prefers-reduced-motion enabled every image swap is instant while the focus trap, keyboard navigation and captions keep working exactly as before.

Install

Add the @te registry to your components.json once:

{
  "registries": {
    "@te": "https://templateempire.io/r/{name}.json"
  }
}

Then install the component:

npx shadcn@latest add @te/modal-lightbox-gallery

Usage

import { ModalLightboxGallery } from "@/components/modal-lightbox-gallery";

export default function Page() {
  return (
    <ModalLightboxGallery
      images={[
        {
          id: "held-light",
          src: "/held-light.jpg",
          alt: "Abstract sun study in warm gradient tones",
          caption: "Held Light No. 4",
          width: 1600,
          height: 1000,
        },
        {
          id: "quiet-horizon",
          src: "/quiet-horizon.jpg",
          alt: "Minimal horizon line dividing two cool gradient tones",
          caption: "Quiet Horizon",
          width: 1600,
          height: 900,
        },
      ]}
    />
  );
}

Props

PropTypeDefaultDescription
imagesReadonlyArray<{ id: string; src: string; alt: string; caption?: string; width: number; height: number }>requiredTwo to twelve images with unique ids and stable dimensions. Malformed or duplicate entries are dropped rather than rendered broken.
initialIdstringundefinedInitially selected image. Falls back to the first valid id.
transitionStyle"crossfade" | "slide" | "scale""crossfade"Image-change treatment while the lightbox is open.
thumbnailPosition"bottom" | "side""bottom"Thumbnail rail placement on wide screens. Narrow screens always stack the rail below the image.
fit"contain" | "cover""contain"Media object-fit treatment for the active image.
backdropOpacitynumber0.78Backdrop opacity, clamped to 0.45 through 0.92.
transitionDurationnumber0.32Image transition duration in seconds, clamped to 0 through 0.7.
radiusnumber20Media and thumbnail corner radius in CSS pixels, clamped to 0 through 40.
classNamestringundefinedAdditional classes merged onto the gallery wrapper.

Customisation

Gallery Lightbox Modal exposes three tokens: lightbox-accent tints the active thumbnail's ring and check badge, lightbox-panel backs the thumbnail rail plus the controls and caption (layered over an opaque background so they stay legible on any photograph), and lightbox-overlay colours the backdrop before backdropOpacity is applied. All three default to the shared semantic tokens, so retheme them from any ancestor without touching the component:

:root {
  --lightbox-accent: var(--color-accent-400, var(--ring));
}

<ModalLightboxGallery
  images={images}
  transitionStyle="slide"
  thumbnailPosition="side"
/>

Frequently asked questions

Is Gallery Lightbox Modal free for commercial use?
Yes. Gallery Lightbox Modal is MIT licensed, so you can use it in personal and commercial projects without attribution.
Is the lightbox accessible for keyboard and screen reader users?
Yes. Activating a thumbnail opens a native dialog element with showModal, so the browser provides the focus trap, top layer rendering and Escape handling, and the page behind it becomes inert. The dialog has a labelled accessible name that updates with the active image, Close, Previous and Next are real buttons, background scroll is locked while open, and closing returns focus to the exact thumbnail that opened it. Malformed or empty image data is dropped safely rather than rendering a broken image or an unreachable focus target.
How does the image transition work, and what happens with reduced motion?
Motion animates only opacity, and for the slide style a bounded translate no larger than 32 pixels, inside a fixed-height stage so switching images never shifts the surrounding layout. Only the two images adjacent to the active one are preloaded after opening. With prefers-reduced-motion enabled every image swap is instant, with no slide, scale or crossfade travel, while the focus trap, arrow keys, captions and thumbnail selection all keep working exactly as before.

Related components

Want the full page this belongs to?Template Empire builds complete Next.js templates with this motion system throughout. Browse the paid templates that pair with these free components.Explore Template Empire templates