DP
Image Gallery and Modal Component in React

How to make a simple image gallery and modal component in React with Tailwind CSS


After figuring out different approaches to making an image gallery with a modal window to view the images, I have decided to create a version with just React and Tailwind CSS. Here is the final code with a few adjustments.

Gallery.jsx file

import { useState } from "react";
import Modal from "./Modal";

export default function Gallery({images}) {
  const [modalOpen, setModalOpen] = useState(false);
  const [currentImage, setCurrentImage] = useState(0);

  return (
    <section className="m-10 grid grid-cols-1 justify-items-center gap-10 sm:grid-cols-2 lg:grid-cols-3">
      {images.map((image) => (
        <button
          key={image.id}
          className="cursor-pointer"
          onClick={()=> {
            setModalOpen(true);
            setCurrentImage(image.id);
          }}
        >
          <img
            src={image.src}
            alt={`Image ${image.id + 1}`}
            className="h-80 w-60 rounded object-cover"
          />
        </button>
      ))}
      {modalOpen && (
        <Modal
          setModalOpen={setModalOpen}
          setCurrentImage={setCurrentImage}
          images={images}
          currentImage={currentImage}
        />
      )}
    </section>
  );
}

images.js file

import img1 from "./assets/images/1.jpg";
import img2 from "./assets/images/2.jpg";
import img3 from "./assets/images/3.jpg";
import img4 from "./assets/images/4.jpg";
import img5 from "./assets/images/5.jpg";

export const images = [
  { id: 0, src: img1, alt: "Image 0 description" },
  { id: 1, src: img2, alt: "Image 1 description" },
  { id: 2, src: img3, alt: "Image 2 description" },
  { id: 3, src: img4, alt: "Image 3 description" },
  { id: 4, src: img5, alt: "Image 4 description" },
];

MainComponent.jsx file

import Gallery from "./components/Gallery";
import { images } from "./images";

export default function MainComponent() {
  return <Gallery images={images} />;
}

Modal.jsx file

export default function Modal({
  setModalOpen,
  setCurrentImage,
  images,
  currentImage,
}) {
  return (
    <section className="fixed inset-0 z-50 flex items-center justify-center bg-black/80">
      <div className="mx-4 max-h-[90vh] w-full max-w-4xl overflow-y-auto rounded bg-white p-6">
        <button
          onClick={()=> setModalOpen(false)}
          className="absolute top-4 right-4 cursor-pointer text-2xl text-gray-100 hover:text-gray-300"
          aria-label="Close modal"
        >
          &times;
        </button>
        <div className="relative">
          <img
            src={images[currentImage].src}
            alt={`Image ${currentImage + 1}`}
            className="mx-auto h-80 w-60 rounded object-cover sm:size-full"
          />
          <div className="my-6 flex justify-center space-x-2">
            {images.map((image) => (
              <button
                key={image.id}
                onClick={()=> setCurrentImage(image.id)}
                className={`h-3 w-3 cursor-pointer rounded-full ${
                  currentImage= image.id ? "bg-black" : "bg-gray-300"
                }`}
              />
            ))}
          </div>
          <button
            onClick={()=>
              setCurrentImage((prev)=>
                prev > 0 ? prev - 1 : images.length - 1,
              )
            }
            className="absolute top-1/2 left-2 -translate-y-1/2 cursor-pointer rounded-full bg-black/50 px-2 pb-3 text-4xl text-white hover:bg-black/60"
          >

          </button>
          <button
            onClick={()=>
              setCurrentImage((prev)=>
                prev < images.length - 1 ? prev + 1 : 0,
              )
            }
            className="absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer rounded-full bg-black/50 px-2 pb-3 text-4xl text-white hover:bg-black/60"
          >

          </button>
        </div>
      </div>
    </section>
  );
}

Live version

This version uses the images from my blog posts as examples (click on the images to open the modal window).

Styling has been slightly modified to match the design of the current site.


Thank you for reading.