DEV Community

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

Posted on β€’ Edited on

8 1

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!✨

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo πŸ“Šβœ¨

Top comments (0)

Image of Stellar post

Check out Episode 1: How a Hackathon Project Became a Web3 Startup πŸš€

Ever wondered what it takes to build a web3 startup from scratch? In the Stellar Dev Diaries series, we follow the journey of a team of developers building on the Stellar Network as they go from hackathon win to getting funded and launching on mainnet.

Read more

πŸ‘‹ Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay