Lightbox
Image viewer that morphs from the thumbnail, with swipe, zoom, and pull to close.
- Dependencies (2)
- Registry (1)
Features
Built on top of ramka, unstyled lightbox primitives for React. ramka handles the behavior, gestures, and accessibility. This component adds the styles.
- Morphs from the thumbnail on open and back on close.
- Swipe between images, pull down to close.
- Pinch or double-tap to zoom, then drag to pan.
Use cases
- Photo galleries on a portfolio or travel page.
- Product images on a store page.
- Screenshots in a blog post or changelog.
Installation
pnpm dlx shadcn@latest add @ncdai/lightbox
Usage
import {
Lightbox,
LightboxCaption,
LightboxClose,
LightboxContent,
LightboxCounter,
LightboxFooter,
LightboxHeader,
LightboxItem,
LightboxMedia,
LightboxNext,
LightboxPrevious,
LightboxSlide,
LightboxSlides,
LightboxTrigger,
LightboxZoom,
LightboxZoomIn,
LightboxZoomOut,
} from "@/components/lightbox"<Lightbox>
{photos.map((photo, index) => (
<LightboxTrigger key={photo.src} index={index}>
{({ imageRef }) => <img ref={imageRef} src={photo.src} alt={photo.alt} />}
</LightboxTrigger>
))}
<LightboxContent aria-label="Photos">
<LightboxSlides aria-label="Photos" aria-roledescription="carousel">
{photos.map((photo, index) => (
<LightboxSlide key={photo.src}>
<LightboxItem index={index} caption={photo.caption}>
<LightboxZoom>
<LightboxMedia width={photo.width} height={photo.height}>
<img src={photo.src} alt={photo.alt} />
</LightboxMedia>
</LightboxZoom>
</LightboxItem>
</LightboxSlide>
))}
</LightboxSlides>
<LightboxHeader>
<LightboxZoomOut />
<LightboxZoomIn />
<LightboxClose />
</LightboxHeader>
<LightboxPrevious />
<LightboxNext />
<LightboxFooter>
<LightboxCaption />
<LightboxCounter />
</LightboxFooter>
</LightboxContent>
</Lightbox>The thumbnail and the full image must share the same aspect ratio. Crop the
thumbnail with object-cover.
Composition
Use the following composition to build a Lightbox
Lightbox
├── LightboxTrigger
└── LightboxContent
├── LightboxSlides
│ └── LightboxSlide
│ └── LightboxItem
│ └── LightboxZoom
│ └── LightboxMedia
├── LightboxHeader
│ ├── LightboxZoomOut
│ ├── LightboxZoomIn
│ └── LightboxClose
├── LightboxPrevious
├── LightboxNext
└── LightboxFooter
├── LightboxCaption
├── LightboxCounter
└── LightboxThumbnailStrip
└── LightboxThumbnailStripTrack
└── LightboxThumbnailAPI reference
Props pass through to ramka. See the ramka API reference.
| Part | Notes |
|---|---|
LightboxContent | Includes the portal and backdrop. Needs aria-label. |
LightboxHeader, LightboxFooter | Hide while pulling to close. The footer also hides while zoomed. |
LightboxClose, LightboxZoomIn, LightboxZoomOut, LightboxPrevious, LightboxNext | Render a Button with variant="secondary" and size="icon", both overridable. |
createLightboxHandle | Returns a handle with open(index), close(), and goTo(index). Pass it to Lightbox as handle. |
Spacing
Set on LightboxContent, for example md:[--lb-inset-x:2rem].
| Variable | Default |
|---|---|
--lb-inset-top | 4rem, 4.5rem from md |
--lb-inset-bottom | 4rem, 4.5rem from md, 8rem with thumbnails |
--lb-inset-x | 0, 4.5rem from md |
Data attributes
LightboxContent is a group/lightbox, so children can use group-data-zoomed/lightbox:hidden and the like.
| Attribute | Element |
|---|---|
data-pulling, data-pull-dismissing, data-zoomed | LightboxContent |
data-active | LightboxItem, LightboxThumbnail |
Examples
Thumbnails
Single image
scrollToZoom lets the mouse wheel zoom, and maxZoom caps it.
Open from code
Without a trigger, the lightbox fades in instead of morphing.
Next.js Image
Use sizes="100vw" on the full image and skip fill.
Accessibility
Escapecloses and returns focus to the trigger.- Arrow keys move between images, or pan when zoomed.
HomeandEndjump to the ends. +,-, and0zoom in, out, and reset.- The caption and counter are announced on change.
- Button labels are in English. Pass
childrento translate them. - With
prefers-reduced-motion, the morph becomes a fade and the thumbnail strip jumps.
Credits
- Artur Bień
- Photos by Marina Lobato, diGital Sennin, Thai Tong, Tam Dang Ngoc, Jonathan Ouimet, Tron Le, and Ngô Thanh Tùng on Unsplash
References
- ramka
- Gestures — pull, zoom, and the CSS variables they expose
- View Transition API
License and usage
- Free to use and modify in both personal and commercial projects.
- Attribution is appreciated but not required.
- Released under the MIT License.