Creating blur placeholders for Next.js images
When users visit my blog, I don’t want them to see an empty space while an image loads. Instead, I want to show a blurred, low-quality version of the image as a placeholder. This is a common technique used by many websites, and Next.js’ Image component has built-in support for these placeholders.
My blog uses next-mdx-remote to render MDX files into React components. This library allows me to map HTML tags to React components, which lets me replace img
with a CustomImage
component.
<MDXRemote
source="![An image](https://example.com/image.jpg)"
components={{ img: CustomImage }}
/>
The CustomImage
component receives the regular img
props, and uses sharp
to generate a low-quality version of the image. Sharp is also used to get the width and height of the image, which is required by the next/image
component to prevent layout shifts. Then, the low-quality image is converted to a base64 string and passed to the next/image
component as the blurDataURL
prop.
import Image from "next/image";
import sharp from "sharp";
async function CustomImage(props) {
const sharpImage = sharp(path.join(process.cwd(), "public", props.src)); // Get image path
const { width, height } = await sharpImage.metadata(); // Get image dimensions
const placeholder = await sharpImage.resize(10).toBuffer(); // Resize to 10px wide
const base64 = placeholder.toString("base64"); // Convert to base64 string
const blurDataURL = `data:image/png;base64,${base64}`; // Prepend data URL
return (
<Image
{...props} // Pass through original props, e.g. `alt`
placeholder="blur"
blurDataURL={blurDataURL}
width={width}
height={height}
className="rounded-lg drop-shadow-sm"
sizes="(max-width: 896px) 100vw, 896px"
/>
);
}
It’s also useful to add styles and other props to the base next/image
component — I’ve added a border radius and drop shadow, and set the sizes
prop to prevent the image from being larger than the viewport.