DEV Community

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

Posted on • Updated 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!