Skip to main content

How to Create a JavaScript Modal Gallery

Saleh is an experienced Web Developer and uses his knowledge and experience to guide people looking to learn Web Dev and new technologies

JavaScript Modal Gallery

JavaScript Modal Gallery

In this tutorial, we will be creating a gallery using JavaScript. The basic idea is that when a user clicks an image, a larger version should be opened in a modal. Then the user can navigate to the next or previous image using buttons.

Create a Grid of Images

Firstly, we are going to create a grid of images using CSS grid. You can create a modal using one image too, but many images is more realistic and can be used for the lightbox part too.

HTML Markup

Any images can be used for this tutorial. The HTML markup is very simple:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script async src="https://kit.fontawesome.com/6cc05e1e8e.js" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="./style.css">
    <meta charset="UTF-8" />
</head>

<body>
    <div class="main">
        <h1>Gallery</h1>
        <div class="gallery">
            <div class="gallery__item">
                <img src="./img/1.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/2.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/3.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/4.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/5.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/6.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/7.jpg" />
            </div>
            <div class="gallery__item">
                <img src="./img/8.jpg" />
            </div>
        </div>
    </div>
</body>

</html>

You may notice a few things here. Firstly, I have imported font awesome for the icon of the close button. I have also linked the style.css, which will contain our CSS. We have 8 images, each of which are in a div called gallery__item.

The CSS is quite straight forward. We are using flex box on our main container to centre everything both vertically and horizontally. Next, we are using CSS grid to created a grid of images which has 4 columns and 2 rows.

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

.main {
    width: 100%;
    flex-direction: column;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px 0px 60px 0px;
}

h1 {
    margin: 10px 0px 30px 0px;
    font-family: cursive;
    color: rgb(0, 6, 90);
    font-size: 50px;
}

.gallery {
    display: grid;
    width: 90%;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 10px;
}

.gallery__item {
    cursor: pointer;
    overflow: hidden;
    border-radius: 4px;
}

.gallery__item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: 0.3s ease-in-out;
}

.gallery__item img:hover {
    transform: scale(1.1);
}

@media (max-width: 950px) {
    .gallery {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 550px) {
    .gallery {
        grid-template-columns: repeat(1, 1fr);
    }
}

To make the gallery responsive, we are using media queries which will convert the 4 column layout to 2 columns in tablets and a single column in mobiles.

Your gallery should be looking like this now:

Gallery

Gallery

JavaScript

Our HTML and CSS part is done for now. Next we need to create the JS code for opening an image when clicked. Firstly, create a script.js file and link it to your index.html by placing the following code in your head section.

<script defer src="./script.js"></script>

Getting the Image Src

Firstly, we need to create a function that gives us the information of an image such as its attributes etc. when it is clicked. To do this, will run a forEach loop on all the images and console.log() the URL of the image when an it is clicked.

const images = document.querySelectorAll(".gallery__item img");
let imgSrc;
// get images src onclick
images.forEach((img) => {
    img.addEventListener("click", (e) => {
        imgSrc = e.target.src;
        console.log(imgSrc)
    });
});

Basically, what this code is doing is that a click event listener is added to each image using the loop. Then the URL of the image is stored in the variable imgSrc using e.target.src.

Creating the Modal

Now we will create a function that will create an empty modal every time we click on an image.

//creating the modal
let imgModal = () => {
    const modal = document.createElement("div");
    modal.setAttribute("class", "modal");
    //add the modal to the main section or the parent element
    document.querySelector(".main").append(modal);
};

Here we are simple creating a div with the class modal and then appending it to our parent element, in this case .main
Next, we need to call this function within the click function inside the loop.

imgModal();

To style the modal, we will use the .modal class and add the following code to the style.css.

Read More From Owlcation

/*Image modal*/

.modal {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(0, 0, 0, 0.733);
    margin-top: -1px;
    animation: zoom 0.3s ease-in-out;
}

@keyframes zoom {
    from {
        transform: scale(0);
    }
    to {
        transform: scale(1);
    }
}

The animation is not necessary but it improves the look.

Adding Image to the Modal

Now we need to create the image and add it to the modal. The URL of the image will be the one we previously stored in the imgSrc variable. We will access this using a parameter in our function that we can pass when we call it.

//creating the modal
let imgModal = (src) => {
    const modal = document.createElement("div");
    modal.setAttribute("class", "modal");
    //add the modal to the main section or the parent element
    document.querySelector(".main").append(modal);
    //adding image to modal
    const newImage = document.createElement("img");
    newImage.setAttribute("src", src);
    modal.append(newImage)
};

And we can pass the imgSrc variable when call the function. Lastly, we need to style the image:

.modal img {
    width: 50%;
    object-fit: cover;
}

Creating the Close Button

Finally, we need to create a close button to close the modal. For this we will first create an i element and add the font awesome class to it for the icon. Next we will create a simple function that will remove the modal when the icon is clicked.

//creating the close button
const closeBtn = document.createElement("i");
closeBtn.setAttribute("class", "fas fa-times closeBtn");
//close function
closeBtn.onclick = () => {
    modal.remove();
};
modal.append(newImage, closeBtn);

Also style the icon:

.closeBtn {
    color: rgba(255, 255, 255, 0.87);
    font-size: 25px;
    position: absolute;
    top: 0;
    right: 0;
    margin: 20px;
    cursor: pointer;
    transition: 0.2s ease-in-out;
}

.closeBtn:hover {
    color: rgb(255, 255, 255);
}

Your Gallery should be functioning like this now:

javascript_gallery

Image Navigation

Now we need to create the navigation buttons and functions that will allow the user to move to the next or previous image.

Creating the Buttons

Firstly we will create 2 buttons, next and previous. Each will have a class and an onclick event. Each button is a font awesome icon and has a function that will either move the image to the next one or previous one.

//next and previous buttons
const nextBtn = document.createElement("i");
nextBtn.setAttribute("class", "fas fa-angle-right nextBtn");
// change the src of current image to the src of next image
nextBtn.onclick = () => {
    newImage.setAttribute("src", nextImg())
};
const prevBtn = document.createElement("i");
prevBtn.setAttribute("class", "fas fa-angle-left prevBtn");
// change the src of current image to the src of pevious image
prevBtn.onclick = () => {
    newImage.setAttribute("src", prevImg())
}
modal.append(newImage, closeBtn, nextBtn, prevBtn);

Basically what we are doing here is that the src of the current image in the modal is being changed to the src returned by the functions.

Image Index

We will first create a variable imgIndex at the start of the script. This variable will contain the index, or position, of the current image in the images array. The current image index will be equal to i, in the first function we created.

const images = document.querySelectorAll(".gallery__item img");
let imgIndex
let imgSrc;
// get images src onclick
images.forEach((img, i) => {
    img.addEventListener("click", (e) => {
        imgSrc = e.target.src;
        //run modal function
        imgModal(imgSrc);
        //index of the current image
        imgIndex = i;
    });
});

In the above code, i is a built-in parameter that gives the index of the current image that was clicked. Now we will use this imgIndex to find the URL of the next image.

Next, we will create the nextImg() and prevImg() functions. Each of the functions will return the new image src.

In the nextImg function, we will add 1 to the index every time the function runs. We will find the URL of the next image by using this new value of the imgIndex and finding the corresponding image in the array. The if statement will move to the first image if we are currently on the last image.

In the prevImg function, we will subtract 1 from the index every time the function runs. In this case, the if statement will check if we are on the first image.

//next image function
let nextImg = () => {
    imgIndex++;
    //check if it is the the last image
    if (imgIndex >= images.length) {
        imgIndex = 0
    }
    //return src of the new image
    return images[imgIndex].src;
};
//previous image function
let prevImg = () => {
    imgIndex--;
    console.log(imgIndex);
    //check if it is the first image
    if (imgIndex < 0) {
        imgIndex = images.length - 1
    }
    //return src of previous image
    return images[imgIndex].src
}

And you are done!

Your gallery should be functioning like this now:

Gallery

Gallery

Complete JavaScript Code

const images = document.querySelectorAll(".gallery__item img");
let imgIndex
let imgSrc;
// get images src onclick
images.forEach((img, i) => {
    img.addEventListener("click", (e) => {
        imgSrc = e.target.src;
        //run modal function
        imgModal(imgSrc);
        //index of the next image
        imgIndex = i;
    });
});
//creating the modal
let imgModal = (src) => {
    const modal = document.createElement("div");
    modal.setAttribute("class", "modal");
    //add modal to the parent element 
    document.querySelector(".main").append(modal);
    //adding image to modal
    const newImage = document.createElement("img");
    newImage.setAttribute("src", src);
    //creating the close button
    const closeBtn = document.createElement("i");
    closeBtn.setAttribute("class", "fas fa-times closeBtn");
    //close function
    closeBtn.onclick = () => {
        modal.remove();
    };
//next and previous buttons
const nextBtn = document.createElement("i");
nextBtn.setAttribute("class", "fas fa-angle-right nextBtn");
// change the src of current image to the src of next image
nextBtn.onclick = () => {
    newImage.setAttribute("src", nextImg())
};
const prevBtn = document.createElement("i");
prevBtn.setAttribute("class", "fas fa-angle-left prevBtn");
// change the src of current image to the src of pevious image
prevBtn.onclick = () => {
    newImage.setAttribute("src", prevImg())
}
modal.append(newImage, closeBtn, nextBtn, prevBtn);
};

//next image function
let nextImg = () => {
    imgIndex++;
    //check if it is the the last image
    if (imgIndex >= images.length) {
        imgIndex = 0
    }
    //return src of the new image
    return images[imgIndex].src;
};
//previous image function
let prevImg = () => {
    imgIndex--;
    console.log(imgIndex);
    //check if it is the first image
    if (imgIndex < 0) {
        imgIndex = images.length - 1
    }
    //return src of previous image
    return images[imgIndex].src
}

This content is accurate and true to the best of the author’s knowledge and is not meant to substitute for formal and individualized advice from a qualified professional.

Related Articles