Handling image loading and error state in Next.js

A guide on how to use placeholder and onError props in Next.js

Wednesday, November 17, 2021

loading timber

How to create a loading and error state placeholder for images?

TL;DR

Check the full code here

Long version


Creating a basic image

next/image provides an easy way to create an image.

NOTE: If you are using Next version 13+, import from next/legacy/image

.jsx
123import Image from 'next/image' <Image src="https://i.imgur.com/gf3TZMr.jpeg" alt="Some alt text" />

However, we still need to configure some properties to cater to our specific needs, such as:


The GIF below shows what a user will see for an image loaded using a slow internet connection.

An image of a blog post

It gives the impression that something is wrong with our app.


How to handle the loading state?

Simply adding the placeholder and blurDataURL will do the trick.

.jsx
12345<Image src="https://i.imgur.com/gf3TZMr.jpeg" placeholder="blur" blurDataURL="/assets/image-placeholder.png"/>

The code will yield the following result:

An image of a blog post

There's a brief delay before the placeholder is loaded because even the placeholder image is needed to be fetched from the server.

If we need to make sure that there's an immediate placeholder to the image, refer to this guide on how to create a dynamic image placeholder

The good thing is that once the placeholder image is loaded, all other images that use the same asset will display the placeholder immediately.

An image of a blog post

What happens if there's an error when loading the image

One possibility is that the user will stare at the placeholder for eternity.

An image of a blog post

Or this sadder version which shows the alt and much space.

An image of a blog post

It is not fun to see too much unnecessary space, is it?



How to display another image during an error state?

We can replace the value of src with the path to error image in the onError callback when an error happens.

.jsx
123456789const [src, setSrc] = React.useState('https://i.imgur.com/gf3TZMr.jpeg'); <Image {...props} src={src} placeholder="blur" blurDataURL="/assets/image-placeholder.png" onError={() => setSrc('/assets/image-error.png')}/>
An image of a blog post

I believe it's much better.


Putting all the code together

To make the behavior easy to replicate, we can create a custom image component.

.jsx
1234567891011121314function CustomImage({alt, ...props}) { const [src, setSrc] = React.useState(props.src); return ( <Image {...props} src={src} alt={alt} // To fix lint warning onError={() => setSrc('/assets/image-error.png')} placeholder="blur" blurDataURL="/assets/image-placeholder.png" /> );}

Conclusion

When a web application displays many images, it is a good idea to give immediate feedback to the user of what is happening. One way to address this is to use an alternate image to show the current state of an image.