DEV Community

Cover image for Image gallery with modal functionality using Next.js, TypeScript, and Tailwind CSS
Sanjana Kumari
Sanjana Kumari

Posted on • Updated on

Image gallery with modal functionality using Next.js, TypeScript, and Tailwind CSS

Introduction:

In this beginner-friendly tutorial, we'll embark on an exciting journey to create a simple yet elegant image gallery with modal functionality using Next.js, TypeScript, and Tailwind CSS. By the end of this guide, you'll have a visually appealing gallery that you can seamlessly integrate into your Next.js projects.

Setting Up the Project:

Make sure you have Node.js installed. Then, create a new Next.js project with TypeScript by running:

npx create-next-app@latest my-image-gallery --ts

Enter fullscreen mode Exit fullscreen mode

Creating the Image Gallery:

Now that our project is set up, let's start crafting our image gallery component. Within the pages directory, create a new file named index.tsx and fill it with the following code:

export default function ImageGallery() {
  const [selectedImage, setSelectedImage] = useState<string | null>(null);
  const [selectedIndex, setSelectedIndex] = useState<number>(0);
  const [images, setImages] = useState<ImageProps[]>([]);

  useEffect(() => {
    // Initialize image data
    setImages([
      { src: img1Path, alt: "Image 1" },
      // Add other images here...
    ]);
  }, []);

const handleNext = () => {
    const nextIndex =
      selectedIndex === images.length - 1 ? 0 : selectedIndex + 1;
    setSelectedImage(images[nextIndex].src as string);
    setSelectedIndex(nextIndex);
  };

  const handlePrev = () => {
    const prevIndex =
      selectedIndex === 0 ? images.length - 1 : selectedIndex - 1;
    setSelectedImage(images[prevIndex].src as string);
    setSelectedIndex(prevIndex);
  };

  return (
    <div className="flex flex-wrap justify-center w-3/5 mx-auto">
      {images.map((image, index) => (
        <div key={index} className="w-1/3 p-2 " style={{ maxWidth: "320px" }}>
          <Image
            {...image}
            width={320}
            height={200}
            priority
            className=" border-4 border-solid border-purple-800 hover:border-purple-500"
            onClick={() => handleOnClicked(image.src as string, index)}
          />
        </div>
      ))}

      {selectedImage && (
        <ModalComponent
          images={images}
          selectedImage={selectedImage}
          onClose={handleCloseModal}
          onNext={handleNext}
          onPrev={handlePrev}
          selectedIndex={selectedIndex}
        />
      )}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Creating the Modal Component:

Now, let's create the modal component that will showcase the selected image in full size. Within the components directory, create a new file named ModalComponent.tsx and fill it with the following code:

import React from "react";
import Image, { ImageProps } from "next/image";

interface ModalProps {
  images: ImageProps[];
  selectedImage: string | null;
  onClose: () => void;
  onNext: () => void;
  onPrev: () => void;
  selectedIndex: number;
}

export default function ModalComponent({
  images,
  selectedImage,
  onClose,
  onNext,
  onPrev,
  selectedIndex,
}: ModalProps){
  return (
    selectedImage && (
      <div className="fixed inset-0 flex justify-center items-center z-50 bg-black bg-opacity-25">
        <div className="max-w-screen-lg mx-4">
          <div className="bg-white px-4 pb-4">
            <div className="flex flex-row justify-between text-center items-center py-3">
              <span className="text-lg font-semibold">LightBox</span>
              <button
                className=" bg-gray-600 bg-opacity-50 py-1 px-2.5 hover:bg-gray-400
                  hover:bg-opacity-70 transition-all rounded-full text-xl text-white font-bold"
                onClick={onClose}
              >
                &#10005;
              </button>
            </div>
            <div className="relative">
              <button
                className="absolute top-1/2 transform -translate-y-1/2 left-0
               text-white py-6 px-4 md:py-24 md:px-4 text-2xl md:text-5xl"
                onClick={onPrev}
              >
                &lt;
              </button>

              <button
                className="absolute top-1/2 transform -translate-y-1/2 right-0
              text-white py-6 px-4 md:py-24 md:px-4 text-3xl md:text-5xl"
                onClick={onNext}
              >
                &gt;
              </button>

              <div className="absolute bottom-4 left-0 right-0 flex justify-center">
                <span className="text-black text-opacity-80 text-lg font-bold">{`Image ${
                  selectedIndex + 1
                }`}</span>
              </div>

              <Image src={selectedImage} alt="Selected Image" width={660} />
            </div>
          </div>
        </div>
      </div>
    )
  );
};

Enter fullscreen mode Exit fullscreen mode

Conclusion:

Great work!✨ You've built your own dynamic image gallery using Next.js, TypeScript, and Tailwind CSS. Now, let your creativity flow and customize your gallery to make it stand out. Keep exploring, learning, and most importantly, enjoy the coding journey ahead! Happy coding!✨

Top comments (0)