DEV Community

Cover image for Building a Responsive Image Gallery with Next.js, TypeScript, and Tailwind CSS
Sanjana Kumari
Sanjana Kumari

Posted on Edited on

Building a Responsive Image Gallery with Next.js, TypeScript, and Tailwind CSS

Introduction:

In this beginner-friendly tutorial, we'll dive into the world of building a responsive image gallery with modal functionality using Next.js, TypeScript, and Tailwind CSS. By the end of this tutorial, you'll have a beautiful and functional image gallery that you can integrate into your Next.js projects.

Setting Up the Project:

To get started, make sure you have Node.js installed on your machine. We'll be using Next.js, a React framework, to build our project. Create a new Next.js project with TypeScript support by running the following command in your terminal:

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

Enter fullscreen mode Exit fullscreen mode

Creating the Image Gallery:

We'll start by creating our image gallery component. In your pages directory, create a new file named index.tsx and add the following code:

// pages/index.tsx

"use client";

import React, { useState } from "react";
import Image from "next/image";
import ImageViewer from "../components/ImageViewer";
import img1Path from "@/assets/Images/Img-1.jpg";
import img2Path from "@/assets/Images/Img-2.jpg";
import img3Path from "@/assets/Images/Img-3.jpg";
import img4Path from "@/assets/Images/Img-4.jpg";
import img5Path from "@/assets/Images/Img-5.jpg";
import img6Path from "@/assets/Images/Img-6.jpg";


export default function IndexPage(){
  const [selectedImage, setSelectedImage] = useState<string | null>(null);
  const [currentImageIndex, setCurrentImageIndex] = useState<number>(0);

const images: ImageProps[] = [
    { src: img1Path, alt: "Image 1" },
    { src: img2Path, alt: "Image 2" },
    { src: img3Path, alt: "Image 3" },
    { src: img4Path, alt: "Image 4" },
    { src: img5Path, alt: "Image 5" },
    { src: img6Path, alt: "Image 6" },
  ];

  const handleOnClicked = (src: string, index: number) => {
    setSelectedImage(src);
    setCurrentImageIndex(index);
  };

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

  const handlePreviousImage = () => {
    const prevIndex =
      currentImageIndex === 0 ? images.length - 1 : currentImageIndex - 1;
    setSelectedImage(images[prevIndex].src as string);
    setCurrentImageIndex(prevIndex);
  };

  return (
    <div className="min-h-screen flex flex-col">
      {selectedImage && (
        <ImageViewer
          selectedImage={selectedImage}
          onNext={handleNextImage}
          onPrev={handlePreviousImage}
        />
      )}
      <div className="flex flex-row flex-wrap gap-3 justify-center px-3 md:px-0">
        {images.map((image, index) => (
          <Image
            key={index}
            {...image}
            className="border-4 border-solid border-blue-900  w-40 cursor-pointer hover:border-blue-500"
            onClick={() => handleOnClicked(image.src as string, index)}
          />
        ))}
      </div>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

Creating the Modal Component:

Next, let's create the modal component that will display the selected image. In your components directory, create a new file named ImageViewer.tsx and add the following code:

// components/ImageViewer.tsx
import React from "react";
import Image from "next/image";

interface ImageViewerProps {
  selectedImage: string;
  onNext: () => void;
  onPrev: () => void;
}

const ImageViewer: React.FC<ImageViewerProps> = ({
  selectedImage,
  onNext,
  onPrev,
}) => {
  return (
    <div className="flex justify-center">
      <div className="relative">
        <Image
          src={selectedImage}
          alt={selectedImage}
          style={{
            width: 1018,
            maxWidth: "100%",
          }}
          className="py-2"
        />

        <button
          className="absolute top-1/2 transform -translate-y-1/2 left-0 text-white py-14 px-4 md:py-28 md:px-5 text-3xl md:text-5xl"
          onClick={onPrev}
        >
          &lt;
        </button>
        <button
          className="absolute top-1/2 transform -translate-y-1/2 right-0 text-white py-14 px-4 md:py-28 md:px-5 text-3xl md:text-5xl"
          onClick={onNext}
        >
          &gt;
        </button>
      </div>
    </div>
  );
};

export default ImageViewer;

Enter fullscreen mode Exit fullscreen mode

Conclusion:

Congratulations! You've successfully built a responsive image gallery with modal functionality using Next.js, TypeScript, and Tailwind CSS. Feel free to customize the design and functionality further to suit your project's needs. Happy coding!✨

(Note: Replace // Define your image data here in the index.tsx file with your actual image data.)

Top comments (2)

Collapse
 
shubhamtiwari909 profile image
Shubham Tiwari • • Edited

Few pointers -

  • For adding code blocks in your blogs, add the language extension after the 3 backticks like this
    Image description
    It will show the code just like code editors show for JS code

  • For this code

const nextIndex =  currentImageIndex === images.length - 1 ? 0 : currentImageIndex + 1;
Enter fullscreen mode Exit fullscreen mode

Could be replaced by this

currentImageIndex = (currentImageIndex + 1) % images.length;
Enter fullscreen mode Exit fullscreen mode

Does the same work

Collapse
 
theedgebreaker profile image
Sanjana Kumari •

Thanks for the insightful comments!
I'll be sure to add language extensions to code blocks in future posts. And you're spot on about using the modulo operator – it's a cleaner solution. I'll update the post accordingly.

Appreciate your input!