DEV Community

qian
qian

Posted on

Beautifying the HTMLImageElement not-loaded/errored status display, react component

background

  • Browser's native image not loaded status doesn't look good, I'd like not to use it.
  • I am using react.

ideas

  • Determine if the image is loaded successfully by onLoaded event.
  • If loaded successfully show the HTMLImageElement, if not show the custom error component while HTMLImageElement is hidden (visibility: hidden).

how it looks like

fail

Image description

fail with alt on it

Image description

success

Image description

tips

  • When load failed, the HTMLImageElement can't be set to display: none, the HTMLImageElement needs to be in the document tree. Also the HTMLImageElement should to be invisible and looks like not placed in the web page, so use the grid display to implement this.

  • every time the image is changed, will reload again, so need to set loaded status to false first.

reference



import { cn } from "@/lib/utils";
import { Image } from "lucide-react";
import { useEffect, useState } from "react";
interface ImageProps {
  src: string;
  iconSize?: number;
  className?: string;
  alt?: string;
  showAlt?: boolean;
}

const BeautyImage = ({
  src,
  iconSize = 16,
  className = "",
  alt = "",
  showAlt = false,
}: ImageProps) => {
  // load successfully or not
  const [imageLoaded, setImageLoaded] = useState(false);

  /**
   * onLoad event
   */
  const onImageLoad = () => {
    setImageLoaded(true);
  };

  /**
   * everytime the src changes, set load status to fail
   */
  useEffect(() => {
    setImageLoaded(false);
  }, [src]);

  return (
    <div
      className={cn(
        "flex flex-col justify-center items-center text-xs text-ttertiary",
        className
      )}
    >
      <div
        className={cn(
          "grid",
          imageLoaded
            ? "grid-rows-[1fr] opacity-100"
            : "grid-rows-[0fr] opacity-0"
        )}
      >
        <div className="overflow-hidden">
          <img className="rounded-full" src={src} onLoad={onImageLoad} />
        </div>
      </div>
      {/* custom error component */}
      {!imageLoaded && (
        <div className="flex flex-col items-center justify-center">
          <Image size={iconSize} />
          {showAlt && alt && <p>{alt}</p>}
        </div>
      )}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Top comments (0)