Membuat Image Viewer Sederhana Menggunakan ReactJs

Komponen image viewer ini digunakan pada sebuah project saya yang hanya dibutuhkan untuk melihat sebuah gambar menjadi lebih detail, dimana saat dibuka menggunakan smartphone gambarnya harus bisa di zoom.

Sebelumnya kami menggunakan sebuah library untuk hal ini, namun setelah dipertimbangkan lagi fitur pada library ini sangat banyak sekali namun yang kita butuhkan hanya lah untuk sebuah view image atau untuk melihat sebuah gambar pada dengan ukuran yang lebih besar dan jelas.

Jika menggunakan new tab di browser untuk membuka gambar tersebut terasa kurang bagus untuk user experience nya.

Oleh karena itu dibuatlah sebuah komponen yang berfungsi hanya untuk melihat gambar dengan ukuran lebih besar sepenuh layar atau bisa di zoom saat di mobile device.

Berikut Adalah komponen snippetnya:

1. Image Viewer Menggunakan Tailwind

import React, { ReactNode, useCallback, useState } from "react"

interface ImageViewerDialogProps {
  url: string
  children: ReactNode
}

const ImageViewerDialog: React.FC<ImageViewerDialogProps> = ({
  url,
  children,
}) => {
  const [isOpen, setIsOpen] = useState(false)

  const openModal = () => setIsOpen(true)
  const closeModal = () => setIsOpen(false)

  const handleBackgroundClick = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      if (e.target === e.currentTarget) {
        closeModal()
      }
    },
    []
  )

  return (
    <div>
      <div onClick={openModal}>{children}</div>
      {isOpen && (
        <div
          onClick={handleBackgroundClick}
          className="fixed top-0 left-0 w-full h-full transition-all ease-in-out
         bg-black bg-opacity-80 z-50 flex justify-center items-center"
        >
          <img
            src={url}
            alt="Image View"
            className="max-w-full max-h-full block"
          />
          <button
            autoFocus
            aria-label="Close Image Viewer Dialog"
            onClick={closeModal}
            className="absolute w-10 h-10 top-4 right-4 text-white bg-red-500 hover:bg-red-700
            focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50 rounded-full p-2"
          >
            <span className="text-white font-bold"></span>
          </button>
        </div>
      )}
    </div>
  )
}

export default ImageViewerDialog

2. Image Viewer Inline Style

Pada komponen ini kita berusaha mengikuti behavior seperti yang ada pada component yang menggunakan tailwind diatas, yaitu untuk handling on hover atau on focus nya.

import React, { useState, useCallback } from "react";

type Props = {
  url: string;
  children: React.ReactNode;
};

const ImageViewerDialog = ({ url, children }: Props) => {
  const [isOpen, setIsOpen] = useState(false);
  const [isHovered, setIsHovered] = useState(false);
  const [isFocused, setIsFocused] = useState(false);

  const openModal = () => setIsOpen(true);
  const closeModal = () => setIsOpen(false);

  const handleBackgroundClick = useCallback((e: any) => {
    if (e.target === e.currentTarget) {
      closeModal();
    }
  }, []);

  const handleMouseEnter = () => setIsHovered(true);
  const handleMouseLeave = () => setIsHovered(false);
  const handleFocus = () => setIsFocused(true);
  const handleBlur = () => setIsFocused(false);

  const createStyle = (styles: unknown) => styles as React.CSSProperties;

  const overlayStyle = createStyle({
    position: "fixed",
    top: 0,
    left: 0,
    width: "100%",
    height: "100%",
    transition: "all ease-in-out",
    backgroundColor: "rgba(0, 0, 0, 0.8)", // bg-black with opacity 80%
    zIndex: 50,
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
  });

  const imageStyle = createStyle({
    maxWidth: "100%",
    maxHeight: "100%",
    display: "block",
  });

  const baseButtonStyle = createStyle({
    position: "absolute",
    width: "40px",
    height: "40px",
    top: "16px",
    right: "16px",
    color: "white",
    backgroundColor: "#f56565", // bg-red-500
    borderRadius: "50%",
    padding: "8px",
    cursor: "pointer",
  });

  const hoverStyle = createStyle({
    backgroundColor: "#c53030", // bg-red-700
  });

  const focusStyle = createStyle({
    outline: "2px solid #f56565", // ring-2 ring-red-500
    outlineOpacity: 0.5,
  });

  const buttonStyle = createStyle({
    ...baseButtonStyle,
    ...(isHovered ? hoverStyle : {}),
    ...(isFocused ? focusStyle : {}),
  });

  return (
    <div>
      <div onClick={openModal}>{children}</div>
      {isOpen && (
        <div style={overlayStyle} onClick={handleBackgroundClick}>
          <img src={url} alt="Image View" style={imageStyle} />
          <button
            autoFocus
            aria-label="Close Image Viewer Dialog"
            onClick={closeModal}
            onMouseEnter={handleMouseEnter}
            onMouseLeave={handleMouseLeave}
            onFocus={handleFocus}
            onBlur={handleBlur}
            style={buttonStyle}
          >
            <span style={{ color: "white", fontWeight: "bold" }}></span>
          </button>
        </div>
      )}
    </div>
  );
};

export default ImageViewerDialog;

Berikut adalah screenshoot nya, bagaimana react image view ini saat di gunakan menggunakan codesandbox.

image-viewer-react.png

Hal Yang bisa di Improve

  • Kita bisa menambahkan wrapper dan icon arrow agar bisa menjadikan viewer component ini untuk photo gallery atau seperti carousel

  • Kita bisa tambahkan juga sebuah loader image untuk meningkatkan user experience

  • Menambahkan props untuk custom style atau button close

Dan masih banyak lagi yang bisa kita improve atau custom sesuai kebutuhan.

Semoga bermanfaat yaa!