Image with fallback component

A React component that renders an image while handling loading errors gracefully. It accepts all standard <img> props and attempts to load the provided src. If the image fails to load, it displays a fallback instead, in this case, an Lucide icon called ImageOffIcon.

import { type ComponentPropsWithRef, useEffect, useRef, useState } from "react";

import { ImageOffIcon } from "lucide-react";

export function ImageWithFallback(props: ComponentPropsWithRef<"img">) {
  const { src, ...imageProps } = props;

  const loadedRef = useRef(false);
  const [error, setError] = useState(false);

  useEffect(() => {
    if (src && !error && !loadedRef.current) {
      loadedRef.current = true;
      const img = new Image();
      img.onerror = () => setError(true);
      img.src = src;
    }
  }, [src, status]);

  if (!src || error)
    return (
      <ImageOffIcon
        style={{ height: imageProps.height, width: imageProps.width }}
      />
    );

  return <img loading="lazy" src={src} {...imageProps} />;
}

Usage

In this example, if the image at https://example.com/profile.jpg fails to load, the component will display the fallback ImageOffIcon while keeping the specified width and height.

<ImageWithFallback
  src="https://example.com/profile.jpg"
  alt="User profile"
  width={100}
  height={100}
/>