DEV Community

Cover image for Filterable Image Gallery with preview using HTML, CSS, and Javascript
Ashutosh Tiwari
Ashutosh Tiwari

Posted on • Originally published at incoderweb.blogspot.com

Filterable Image Gallery with preview using HTML, CSS, and Javascript

Hello friends, today in this blog you will learn how to create a filterable gallery with a preview using HTML, CSS, and Javascript. In our previous blog, we saw how to detect user location using Javascript. Now it's time to create a filterable image gallery. I've also shared many projects related to Javascript. So don't forget to check here.

In this design [Filterable Image Gallery], there are some image category buttons. when you hover on the button, its background color changes into red color and the text color changes into white. When you hover over the images it increases their size and when you click on the image its preview opens in a modal.

You may like these:

The concept of filtering images using Javascript is that on buttons there is a data attribute [data-filterItem=""] in the data attribute the category of images is given and same with images there is a data attribute [data-filterName=""] when you click on the button it takes the button category name and then it takes image names and searches for matching images with that category and add a [show] class on the matching images and the images which are not matching it adds [hide] class.

If you are filling difficulty understanding what am I trying to say, So you can check the source code and preview as well.

Preview is available here.

HTML Code

<!-- ---------------------- Created By InCoder ---------------------- -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Filterable Image Gallery - InCoder</title>
    <link rel="stylesheet" href="main.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
</head>

<body>
    <div class="galleryContainer">
        <div class="items">
            <ul>
                <li><button class="item showAll">All</button></li>
                <li><button class="item" data-filterItem="bag">Bags</button></li>
                <li><button class="item" data-filterItem="glass">Glass</button></li>
                <li><button class="item" data-filterItem="shoe">Shoe</button></li>
                <li><button class="item" data-filterItem="laptop">Laptop</button></li>
                <li><button class="item" data-filterItem="mobile">Mobile</button></li>
                <li><button class="item" data-filterItem="watch">Watch</button></li>
            </ul>
        </div>
        <div class="imageBox">

            <div class="image" data-filterName="watch"><img src="https://drive.google.com/uc?id=1W_YHw1ky5GScu_oFR3Fa2xsA77Mi037B&export=view" alt="Watch"></div>
            <div class="image" data-filterName="bag"><img src="https://drive.google.com/uc?id=1lykvDrCbjrT2u9CWynE40zK39VufHy3z&export=view" alt="Bag"></div>
            <div class="image" data-filterName="mobile"><img src="https://drive.google.com/uc?id=163jK_I6y8nO5D3i0w03uymifabs_ZL_l&export=view" alt="mobile"></div>
            <div class="image" data-filterName="glass"><img src="https://drive.google.com/uc?id=13iUskQ9E2WBxhNlOZ1WG8w-ZyK3IKD1h&export=view" alt="glass"></div>
            <div class="image" data-filterName="shoe"><img src="https://drive.google.com/uc?id=1hTezbGNnjK54_jprSLrbNxF6gQIHFqqc&export=view" alt="shoe"></div>
            <div class="image" data-filterName="laptop"><img src="https://drive.google.com/uc?id=1EkzGCReXAqdi0dcat2WWdioU0MM09STD&export=view" alt="laptop"></div>

            <div class="image" data-filterName="watch"><img src="https://drive.google.com/uc?id=1Z0h0BLzmwx50vl7HQ_kW90t5httnXiH1&export=view" alt="Watch"></div>
            <div class="image" data-filterName="bag"><img src="https://drive.google.com/uc?id=1ULAinHaHzPk1WCpWe2TSWisw8VBV4Uz0&export=view" alt="Bag"></div>
            <div class="image" data-filterName="mobile"><img src="https://drive.google.com/uc?id=19iq87EI68cDYesJJLTN4gnNaD5vo82d0&export=view" alt="mobile"></div>
            <div class="image" data-filterName="glass"><img src="https://drive.google.com/uc?id=1dD4uaF-8ghq1s0JHW9uQCtQHLw9MhzMO&export=view" alt="glass"></div>
            <div class="image" data-filterName="shoe"><img src="https://drive.google.com/uc?id=1sBpjjw_FjIPu0uwAX0IEI9RHUxF3NPsf&export=view" alt="shoe"></div>
            <div class="image" data-filterName="laptop"><img src="https://drive.google.com/uc?id=1itaU8oXioTRRp1IwyqQ-dNo9AW0VEQME&export=view" alt="laptop"></div>

            <div class="image" data-filterName="watch"><img src="https://drive.google.com/uc?id=1G8L4nao4LpW1n-rf8BtCEQ2FAUMugilh&export=view" alt="Watch"></div>
            <div class="image" data-filterName="bag"><img src="https://drive.google.com/uc?id=1MkgIn8fUeq6hkcnUA_q5BB0JQmW-oyDK&export=view" alt="Bag"></div>
            <div class="image" data-filterName="mobile"><img src="https://drive.google.com/uc?id=12Fs0GeOk0x8yr38Nepackc4dju3fKuLa&export=view" alt="mobile"></div>
            <div class="image" data-filterName="glass"><img src="https://drive.google.com/uc?id=1mSCh-fkpC31MTIyu63ylxZJ-12Wib2e5&export=view" alt="glass"></div>
            <div class="image" data-filterName="shoe"><img src="https://drive.google.com/uc?id=18x1w02do6qh-Nw-zLQDDNcrcDYcugL3G&export=view" alt="shoe"></div>
            <div class="image" data-filterName="laptop"><img src="https://drive.google.com/uc?id=1O_mMsBM_VANjTDDbcMN1nmvljPl0kOxP&export=view" alt="laptop"></div>
        </div>
    </div>

    <div class="previewContainer">
        <div class="previewModal">
            <div class="header">
                <h2>Image Preview</h2>
                <div class="closeIcon">
                    <i class="fa-solid fa-xmark"></i>
                </div>
            </div>
            <div class="body">
                <img src="" class="previewImg" alt="Watch">
            </div>
        </div>
    </div>

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

</html>
Enter fullscreen mode Exit fullscreen mode

CSS Code

/* ---------------------- Created By InCoder ---------------------- */

@import url('https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap');
* {
    margin: 0;
    padding: 0;
}

body {
    background-color: rgb(24 24 24 / 93%);
}

.galleryContainer {
    width: 100%;
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
}

.items ul {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
}

.items ul li {
    list-style: none;
    margin: 1.5rem 1rem;
}

.items ul li button.item {
    color: #F53B69;
    cursor: pointer;
    font-size: 1rem;
    border-radius: 2rem;
    padding: .6rem 1.8rem;
    border: 2px solid #F53B69;
    background-color: transparent;
    transition: background-color .3s ease, color .3s ease;
}

.items ul li button.item:hover {
    color: #fff;
    background-color: #F53B69;
}

.item.active {
    color: #fff!important;
    background-color: #F53B69!important;
}

.imageBox {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
}

.imageBox .image img {
    max-width: 16rem;
    max-height: 16rem;
    transition: transform 0.3s ease-in-out;
}

.imageBox .image {
    cursor: pointer;
    overflow: hidden;
    margin: .5rem 2rem;
    position: relative;
    transition: all .5s ease-in-out;
}

.imageBox .image.show {
    animation: show .5s ease;
}

.imageBox .image.hide {
    opacity: 0;
    display: none;
    transform: scale(.5)
}

@keyframes show {
    0% {
        transform: scale(.5)
    }
    100% {
        transform: scale(1)
    }
}

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

.previewContainer {
    top: 0;
    left: 0;
    opacity: 0;
    width: 100%;
    height: 100vh;
    display: flex;
    position: fixed;
    align-items: center;
    pointer-events: none;
    justify-content: center;
    backdrop-filter: blur(2px);
    background: rgb(255 255 255 / 8%);
    transition: opacity 0.3s ease-in-out;
}

.previewContainer.active {
    opacity: 1;
    pointer-events: auto;
}

.previewContainer .previewModal {
    margin: 1rem;
    padding: 1rem 1rem;
    background: #fff;
    border-radius: .4rem;
    transform: translateY(-1rem);
    transition: transform 0.3s ease-in-out;
}

.previewContainer.active .previewModal {
    transform: translateY(0rem);
}

.previewContainer .previewModal .header {
    display: flex;
    margin-bottom: .8rem;
    justify-content: space-between;
}

.previewContainer .previewModal .header h2 {
    font-size: clamp( 1.8rem, 5vw, 2.2rem);
    font-family: 'Ubuntu', sans-serif;
}

.previewContainer .previewModal .header .closeIcon {
    display: grid;
    width: 2.8rem;
    height: 2.8rem;
    font-size: 2rem;
    cursor: pointer;
    border-radius: 50%;
    place-items: center;
    margin-right: .8rem;
    transition: background-color .2s ease-in-out;
}

.previewContainer .previewModal .header .closeIcon:hover {
    background-color: rgb(0 0 0 / 4%);
}

.previewContainer .previewModal .body {
    max-width: 50rem;
}

.previewContainer .previewModal .body img {
    width: 100%;
    max-height: 30rem;
}
Enter fullscreen mode Exit fullscreen mode

Javascript Code

// ---------------------- Created By InCoder ----------------------

let items = document.querySelectorAll('.item');
let showAll = document.querySelector('.showAll');
let closeIcon = document.querySelector('.closeIcon');
let previewImg = document.querySelector('.previewImg');
let images = document.querySelectorAll('.imageBox .image');
let previewContainer = document.querySelector('.previewContainer');

function arrayMatch(clickedItem, allImages) {
    var matchedArray = [];
    for (var i = 0; i < clickedItem.length; ++i) {
        for (var j = 0; j < allImages.length; ++j) {
            if (clickedItem[i] == allImages[j]) {
                matchedArray.push(clickedItem[i]);
            }
        }
    }

    return matchedArray;
}

items.forEach((item) => {
    let filterItem = item.getAttribute('data-filterItem');
    item.addEventListener('click', (e) => {
        for (let i = 0; i < images.length; i++) {
            image = images[i].dataset.filtername;
        }

        for (let i = 0; i < items.length; i++) {
            if (items[i].classList.contains('active')) {
                items[i].classList.remove('active');
            }
        }
        if (!e.path[0].classList.contains('active')) {
            e.path[0].classList.add('active');
        }

        let clickedItem = [];
        for (let a = 0; a < 1; a++) {
            clickedItem.push(e.path[0].dataset.filteritem);
        }

        let allImages = [];
        for (let i = 0; i < images.length; i++) {
            allImages.push(images[i].dataset.filtername);
        }

        let matchingArray = arrayMatch(clickedItem, allImages)[0];

        for (let j = 0; j < images.length; j++) {
            let imagesName = images[j];
            if (imagesName.dataset.filtername == matchingArray) {
                imagesName.classList.remove('hide');
                imagesName.classList.add('show');
            } else {
                imagesName.classList.remove('show');
                imagesName.classList.add('hide');
            }
        }
    });
});

showAll.addEventListener('click', function() {
    for (let i = 0; i < images.length; i++) {
        images[i].classList.remove('hide');
        images[i].classList.add('show');
    }
});

images.forEach((image) => {
    image.addEventListener('click', (e) => {
        let imageUrl = e.path[0].currentSrc;
        previewImg.src = imageUrl
        previewContainer.classList.add('active');
        console.log(e.path[0].currentSrc);
    });
});

closeIcon.addEventListener('click', () => {
    previewContainer.classList.remove('active');
});

previewContainer.addEventListener('click', function(e) {
    if (!document.querySelector('.previewModal').contains(e.target)) {
        previewContainer.classList.remove('active');
    }
});
Enter fullscreen mode Exit fullscreen mode

Discussion (0)