Fix broken images in React with Next.js

By Hunter Becton on May 25, 2022

If your page loads and you see a broken image, it can be pretty jarring and prevent users from exploring your content. The fix is simple: include an image that is a placeholder for the broken image, so nothing falls apart when it doesn't load. This post will describe one way to do this in React using Next.js.

Watch the lesson

Project repo

The code for this project is open-source and available on GitHub. I use Gumroad for those that want to be generous and donate, but no purchase is required. 😊

Grab the code.

Next.js and Tailwind CSS starter

I chose to use Tailwind for styling my Next.js application. You can read more in the Tailwind installation guide if you're interested in how to implement Tailwind into Next.js or another React framework like Create React App or Gatsby.

Next.js image component

Optimizing image performance for the web can be very difficult in some cases, but Next.js makes it simple with the Next.js image component

If you're relying on the HTML image tag, you'd need to consider lazy loading, file size, image size, and modern image formats like WebP. However, the Next.js image component handles all of this for you and includes useful APIs for placeholders and cloud image providers like ImgixCloudinary, and Akamai

The component requires three props: src, height, and width. However, statically imported images or components with the layout prop set to fill do not require the height and width props.

Here's what the Next.js image component might look like before implementing a fallback image component:

import Image from 'next/image'

export default function Home() {
  const images = [
    {
      src: '/images/earth.jpeg',
      alt: 'Earth card',
    },
    // ... more images
  ]

  return (
    <div className="bg-zinc-900 p-4">
      <div className="mx-auto grid max-w-7xl grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
        {images.map((image) => (
          <div key={image.src} className="relative aspect-square">
            <Image
              layout="fill"
              objectFit="cover"
              src={image.src}
              alt={image.alt}
            />
          </div>
        ))}
      </div>
    </div>
  )
}

This code would work great for situations where you were sure the image links would never change, but sometimes that's not always the case. That's where the fallback image component comes in. 

Fallback image component

The fallback image component is a simple wrapper for the Next.js image component. Below is the code for this component:

import { useEffect, useState } from 'react'
import Image from 'next/image'

export const FallbackImage = ({ src, ...rest }) => {
  const [imgSrc, setImgSrc] = useState(src)

  useEffect(() => {
    setImgSrc(src)
  }, [src])

  return (
    <Image
      {...rest}
      src={imgSrc ? imgSrc : '/images/not-found.png'}
      onError={() => {
        setImgSrc('/images/not-found.png')
      }}
    />
  )
}

The component stores the src prop in a state value using the React useState hook. The React useEffect hook watches for changes to the src prop and will update the prop with the state value when it changes.

The real magic happens on the onError event handler, triggered if an error occurs while loading an external file. Inside the handler, the state value function is called and sets the state to a fallback image from the project's public folder.

Now, any time an external file doesn't exist, your user will see a nice fallback image instead of the ugly browser default.

Conclusion

This article examined how to fix broken image links in React using Next.js and a fallback image component. The fallback component is a simple wrapper around the already powerful Next.js image component and uses the onError event to change the image source to a local default image.