Skip to content

Lightbox

Fullscreen dialog for viewing image or video media, with optional gallery navigation.

Forest path
Morning light through a forest path.
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={imageMedia[0]} />
Forest path
Morning light through a forest path.
1 / 3
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={imageMedia} />
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={videoMedia} />
Forest path
Morning light through a forest path.
1 / 3
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={mixedMedia} />
Forest path
Morning light through a forest path.
1 / 3
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={imageMedia} />
Forest path
Morning light through a forest path.
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={imageMedia[0]} />
function LightboxStory({
defaultIndex,
media,
...args
}: LightboxStoryArgs & {media: LightboxProps['media']}): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open lightbox" onClick={() => setIsOpen(true)} />
<Lightbox
{...args}
defaultIndex={defaultIndex}
isOpen={isOpen}
media={media}
onOpenChange={setIsOpen}
/>
</>
);
}
<LightboxStory {...args} media={videoMedia} />
Mountain lake
A clear alpine lake below snow-covered mountains.
2 / 3
function ControlledIndexStory(args: LightboxStoryArgs): React.JSX.Element {
const [isOpen, setIsOpen] = useState(false);
const [index, setIndex] = useState(1);
return (
<>
<div style={{display: 'flex', gap: 8}}>
<Button label="Open gallery" onClick={() => setIsOpen(true)} />
<Button label="Show first" onClick={() => setIndex(0)} />
<Button
label="Show last"
onClick={() => setIndex(imageMedia.length - 1)}
/>
</div>
<Lightbox
{...args}
index={index}
isOpen={isOpen}
media={imageMedia}
onIndexChange={setIndex}
onOpenChange={setIsOpen}
/>
</>
);
}
<ControlledIndexStory {...args} />
Forest path
Morning light through a forest path.
function HookStory(): React.JSX.Element {
const lightbox = useLightbox({media: imageMedia[0]});
return (
<>
<Button label="Open from hook" onClick={() => lightbox.open()} />
{lightbox.element}
</>
);
}
<HookStory />
Forest path
Mountain lake
Desert ridge
Forest path
Morning light through a forest path.
1 / 3
function HookGalleryStory(): React.JSX.Element {
const lightbox = useLightbox({media: imageMedia, hasZoom: true});
return (
<>
<div
style={{
display: 'grid',
gap: 12,
gridTemplateColumns: 'repeat(3, minmax(0, 140px))',
}}>
{imageMedia.map((item, index) => (
<div
key={item.src}
{...lightbox.getTriggerProps(index)}
style={{
border: 0,
borderRadius: 6,
cursor: 'pointer',
overflow: 'hidden',
}}>
<img
alt={item.alt}
src={item.src}
style={{
aspectRatio: '4 / 3',
display: 'block',
objectFit: 'cover',
width: '100%',
}}
/>
</div>
))}
</div>
{lightbox.element}
</>
);
}
<HookGalleryStory />

Fullscreen dialog for viewing image or video media, with optional gallery navigation.

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the dialog.
data-testidstringTest ID applied to the dialog.
defaultIndexnumber0Initial gallery index for uncontrolled usage.
hasAutoPlaybooleanfalseWhether videos autoplay when opened.
hasZoombooleanfalseWhether images can be double-clicked to zoom.
indexnumberControlled gallery index.
isOpen*booleanWhether the lightbox is open.
media*LightboxMedia | ReadonlyArray<LightboxMedia>Media to display.
onIndexChange(index: number) => voidCalled when gallery index changes.
onOpenChange*(isOpen: boolean) => voidCalled when the lightbox requests an open-state change.
refRef<HTMLDialogElement>Ref forwarded to the dialog element.
styleCSSPropertiesInline styles applied to the dialog.