Next.js
If your project is based on Next.js, you may want to take advantage of the next/image component and next/dynamic import to minimize your bundle size.
next/dynamic
In most cases, the lightbox JS code and CSS stylesheets do not need to load with
the initial page load, and loading can be postponed until a user starts
interacting with your application. This fact creates an opportunity to reduce
your initial load bundle size, which can help improve the speed and
responsiveness of your application. To implement this approach in a Next.js
project, you can extract the lightbox-related code and CSS stylesheets into a
separate component and load it dynamically with the next/dynamic
import.
The below example demonstrates the use of next/dynamic
import.
Sandbox
Edit on StackBlitznext/image
The next/image
component provides a more efficient way to handle images in
your Next.js project. You can replace the standard <img>
element with
next/image
via a custom render.slide
function. The below example makes use
of placeholder="blur"
instead of showing a spinner.
import Image from "next/image";
import {
isImageFitCover,
isImageSlide,
useLightboxProps,
useLightboxState,
} from "yet-another-react-lightbox";
function isNextJsImage(slide) {
return (
isImageSlide(slide) &&
typeof slide.width === "number" &&
typeof slide.height === "number"
);
}
export default function NextJsImage({ slide, offset, rect }) {
const {
on: { click },
carousel: { imageFit },
} = useLightboxProps();
const { currentIndex } = useLightboxState();
const cover = isImageSlide(slide) && isImageFitCover(slide, imageFit);
if (!isNextJsImage(slide)) return undefined;
const width = !cover
? Math.round(
Math.min(rect.width, (rect.height / slide.height) * slide.width),
)
: rect.width;
const height = !cover
? Math.round(
Math.min(rect.height, (rect.width / slide.width) * slide.height),
)
: rect.height;
return (
<div style={{ position: "relative", width, height }}>
<Image
fill
alt=""
src={slide}
loading="eager"
draggable={false}
placeholder={slide.blurDataURL ? "blur" : undefined}
style={{
objectFit: cover ? "cover" : "contain",
cursor: click ? "pointer" : undefined,
}}
sizes={`${Math.ceil((width / window.innerWidth) * 100)}vw`}
onClick={
offset === 0 ? () => click?.({ index: currentIndex }) : undefined
}
/>
</div>
);
}
import Lightbox from "yet-another-react-lightbox";
import "yet-another-react-lightbox/styles.css";
import NextJsImage from "../components/NextJsImage";
import image1 from "../../public/images/image01.jpeg";
import image2 from "../../public/images/image02.jpeg";
import image3 from "../../public/images/image03.jpeg";
// ...
return (
<Lightbox
open={open}
close={() => setOpen(false)}
slides={[image1, image2, image3]}
render={{ slide: NextJsImage }}
/>
);
Live Demo
Sandbox
Edit on StackBlitzWith Thumbnails Plugin
In the same way you used next/image
to optimize your slide images, you can use
it to optimize your thumbnails. You can replace the standard <img>
element
with next/image
via a custom render.thumbnails
function.
import Lightbox from "yet-another-react-lightbox";
import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
import "yet-another-react-lightbox/styles.css";
import "yet-another-react-lightbox/plugins/thumbnails.css";
import NextJsImage from "../components/NextJsImage";
import image1 from "../../public/images/image01.jpeg";
import image2 from "../../public/images/image02.jpeg";
import image3 from "../../public/images/image03.jpeg";
// ...
return (
<Lightbox
open={open}
close={() => setOpen(false)}
slides={[image1, image2, image3]}
render={{ slide: NextJsImage, thumbnail: NextJsImage }}
plugins={[Thumbnails]}
/>
);
With Zoom Plugin
Zoom plugin doesn't work well with the Next.js image component. You can use the following approach to take advantage of Next.js image optimization when using Zoom plugin.
import Lightbox from "yet-another-react-lightbox";
import Zoom from "yet-another-react-lightbox/plugins/zoom";
import "yet-another-react-lightbox/styles.css";
import image1 from "../public/images/image01.jpeg";
import image2 from "../public/images/image02.jpeg";
import image3 from "../public/images/image03.jpeg";
// ...
const images = [
image1,
image2,
image3,
// ...
];
const imageSizes = [16, 32, 48, 64, 96, 128, 256, 384];
const deviceSizes = [640, 750, 828, 1080, 1200, 1920, 2048, 3840];
function nextImageUrl(src, size) {
return `/_next/image?url=${encodeURIComponent(src)}&w=${size}&q=75`;
}
const slides = images.map(({ src, width, height }) => ({
width,
height,
src: nextImageUrl(src, width),
srcSet: imageSizes
.concat(...deviceSizes)
.filter((size) => size <= width)
.map((size) => ({
src: nextImageUrl(src, size),
width: size,
height: Math.round((height / width) * size),
})),
}));
// ...
return (
<Lightbox
open={open}
close={() => setOpen(false)}
slides={slides}
plugins={[Zoom]}
/>
);