Lightbox React component
An image lightbox for any grid of photos: the thumbnail morphs into the full view, then arrows, keys and swipes step through, double-click zooms and pans, a swipe down closes, and a thumbnail strip tracks where you are.
When to use the Lightbox component
Use Lightbox wherever people should look at photos properly without leaving the page: product images, portfolios, event albums, user uploads. The thumbnail grows into the full view, so it's always clear which picture opened.
Use showGrid={false} with index when the thumbnails are part of your own layout (a product gallery, a feed) and you only need the viewer.
Installation
Add the Lightbox component to your project with the shadcn CLI. It lands in components/lightbox.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add https://reactframe.com/r/lightbox.jsonOr copy the source by hand and install its dependencies:
npm install motion clsx tailwind-mergeProps
<Lightbox /> accepts 10 props, all optional.
| Prop | Type | Default |
|---|---|---|
| images | { src: string; alt: string; caption?: string; thumb?: string }[] | DEFAULT_IMAGES |
| showGrid Render the clickable thumbnail grid. Turn off to open it yourself with index / onIndexChange. | boolean | true |
| columns | number | 3 |
| index The open image (null = closed). Leave out to let the grid manage it. | number | null | — |
| onIndexChange | (index: number | null) => void | — |
| showThumbnails | boolean | true |
| contained Keep the viewer inside the nearest positioned ancestor instead of covering the page. | boolean | false |
| loop | boolean | true |
| theme | "dark" | "light" | "dark" |
| className | string | — |
- images{ src: string; alt: string; caption?: string; thumb?: string }[]Default: DEFAULT_IMAGES
- showGrid
Render the clickable thumbnail grid. Turn off to open it yourself with index / onIndexChange.
booleanDefault: true - columnsnumberDefault: 3
- index
The open image (null = closed). Leave out to let the grid manage it.
number | null - onIndexChange(index: number | null) => void
- showThumbnailsbooleanDefault: true
- contained
Keep the viewer inside the nearest positioned ancestor instead of covering the page.
booleanDefault: false - loopbooleanDefault: true
- theme"dark" | "light"Default: "dark"
- classNamestring
FAQ
- How do people move between images?
- Arrow buttons, the keyboard's left and right arrows, swiping sideways, or tapping a thumbnail in the strip. Swiping down or pressing Escape closes it.
- Can images be zoomed?
- Yes. Double-click, press Z or use the zoom button for 2x; while zoomed, drag to look around.
- Does it cover the whole page?
- By default it's portalled to the body and covers the viewport. Set contained to keep it inside the nearest positioned container, e.g. a card or a preview.