Lightbox
ProA full-screen, browsable image viewer over Radix Dialog. Give it the image list once and any LightboxTrigger opens it at that index. Page between images with arrow buttons, arrow keys and a thumbnail rail.
Installation#
Usage#
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Anatomy#
import { Lightbox, LightboxTrigger } from "@/components/ui/lightbox"
<Lightbox images={…}>
<LightboxTrigger index={0}>…</LightboxTrigger>
</Lightbox>With Gallery#
Wrap a Gallery tile in a LightboxTrigger with asChild, and give the GalleryItem an action label so it reveals the “See image” pill on hover and opens the viewer on click.
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Single image#
With one image the arrows and the thumbnail rail disappear, so a lone trigger works as a simple click-to-zoom for a single screenshot, with its own pill label.
Stop at the ends#
Paging loops by default: the next arrow on the last image goes back to the first. Set loop to false when the order means something and wrapping around would read as starting over, like the steps of a guide or one page of a paginated gallery. The arrow at each end disappears, and the ← / → keys and a swipe go no further (the image resists the drag and springs back).
Labels#
Every word the viewer speaks or shows, from the dialog name a screen reader announces to the counter and the trigger pill, comes from labels. Pass the keys you want to change; the rest keep their English defaults. The indexed ones are functions that receive the 0-based index and the total, so you can phrase them however your language needs.
API reference#
Lightbox
The root: holds the images and renders the viewer over Radix Dialog (focus trap, scroll lock, Esc). With more than one image, arrows, the arrow keys, the thumbnail rail and a swipe page between them, looping unless loop={false}. LightboxTrigger accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| images* | LightboxImage[] | - | The photos, as { src: string; alt?: string }. |
| open | boolean | - | Controlled open state. Omit for uncontrolled. |
| onOpenChange | (open: boolean) => void | - | Called when the viewer opens or closes. |
| defaultIndex | number | 0 | The image shown first, uncontrolled. |
| loop | boolean | true | Wraps paging around the ends. false stops at the first and last image: the end arrow disappears and keys and swipes go no further. |
| labels | Partial<LightboxLabels> | - | Translatable copy. viewer, close, previous, next and trigger are strings; goToImage, imageOf and counter are (index, total) => string. |
| children | React.ReactNode | - | The triggers. |
LightboxTrigger
Opens the viewer at its index. Renders a <button> and forwards all its props.
| Prop | Type | Default | Description |
|---|---|---|---|
| index* | number | - | Position in the images array to open at. |
| label | React.ReactNode | "See image" | The pill shown on hover and focus. null hides it; ignored with asChild. |
| asChild | boolean | false | Makes the child (a GalleryItem, say) the trigger. It draws no pill and defers to the child's affordance. |