How to filter bootstrap gallery

Creating a basic filter for a bootstrap gallery using HTML and a bit of Javascript is a lot simpler than I thought. You can always go the long way with HTML / CSS / Javascript but if you don’t have much time like me or you want to just focus on getting something else done (again just like me) you can keep it really simple

Here is what we will see after going through this tutorial

Final result of a bootstrap gallery with javascript filter

Nice isn’t it ? It’s also very simple

What is Bootstrap

If you don’t know Bootstrap then you don’t know what you are missing. It is an open source CSS framework that makes web development a lot easier and fun. It also makes your page responsive by default meaning that it looks nice no matter how big (or small) the screen is.

As with any framework, its job is to automate or hide from the user complex / repetitive tasks during web development. You may lose a bit in flexibility but you gain so much in time and effort.

At the time of writing, Bootstrap is in version 5.1 and that’s what we will be using for this tutorial. Be aware that every major version brings considerable changes that may brake configurations made in older version so don’t just point to a new version without testing the webpage first.

Instructions on how to load Boostrap in your code are here

The search box is as you can easily understand the place where you search for your images. Here is the code for it in bootstrap

<div class="row mt-2">
        <div class="col-12 col-md-3 mb-3">
		<input type="text" class="form-control" placeholder="Search cards" aria-label="Search cards" onkeyup="searchFilter()">
	</div>
</div>

Here is the explanation for the classes we use in the first div block

row: the search box will be place in one row all by itself

mt-2: there will have a top margin of 2. It takes values from 0 to 5

The next div block

col-12, col-md-3: In a small smartphone screen the searchbox will take 1/12th of the screen and in medium or higher screen (typically from tablets to laptops to big screens) it will take 1/4th of the screen

mb-3: there will be a bottom margin of 3

onkeyup=”searchFilter()”: This pretty much calls the searchFilter function every time we release a key on the keyboard. This is exactly what makes our filter to apply in realtime while we are typing. The content of the function is written in javascript

Hint: In chrome you can right click on your page and select inspect. There you can chose on top of the page Dimensions: Responsive and you can see how the webpage looks for different resolutions / screens

The input tag pretty much adds the search box in the page.

Now that we created the search box we move over to the image gallery. For this we will use the Bootstrap cards in a grid because it just looks nicer. You can take the code from here

I am going to copy the code for one card. You can add as many cards you want by just copying the contents of the <div class=”col”> including itself

            <div class="row row-cols-1 row-cols-md-3 g-4">
                <div class="col">
                    <div class="card h-100">
                        <img src="https://source.unsplash.com/random?orientation=landscape&sig=123" class="card-img-top"
                            style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                        <div class="card-body  d-flex flex-column">
                            <h5 class="card-title">Random Card One</h5>
                            <p class="card-text">Lorem ipsum dolor sit amet.</p>
                            <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                        </div>
                    </div>
                </div>
            </div>

Here is an explanation of the various classes

row row-cols-1 row-cols-md-3: We will place the cards in rows. For small screens (smartphones) we will use one card per row and for medium larger screens (tablets and above) we will use 3 cards per row

h-100: each card will have the same height

style=”width:100% ; height:15vw ; object-fit:cover;” : Normally you would write all the styling code in a separate css file but for the sake of clarity on this example it’s in the HTML code. What this does is to make sure that the different images in the card take up the same exact space on all cards. The object-fit:cover ensures the image is zoomed in instead of being stretched

You can copy this code multiple times to create more cards.

Hint: I use Unsplash’s random images each time the code is run to make this example even more fun. To get a different image per card just change the number in the sig parameter.

Wrapping all HTML in a container

The benefit is not really visible in our example but if you want to take advantage of Bootstrap’s default grid layout (and you should unless you know what you are doing) you need to enclose you code in this container

<div class="container">
  <!-- Content here -->
</div>

Javascript for the Filter

Now that we finished with the HMTL / styling part of the web page it’s time to make our real-time filter working with Javascript. As we mentioned above, each key we release on the keyboard invokes the searchFilter function that has our filter implemented

Here is the code:

    <script>
        var searchFilter = () => {
            const input = document.querySelector(".form-control");
            const cards = document.getElementsByClassName("col");
            let filter = input.value
            for (let i = 0; i < cards.length; i++) {
                let title = cards[i].querySelector(".card-body");
                if (title.innerText.toLowerCase().indexOf(filter.toLowerCase()) > -1) {
                    cards[i].classList.remove("d-none")
                } else {
                    cards[i].classList.add("d-none")
                }
            }
        }
    </script>

input: constant variable that basically stores the keyboard strokes as we type

cards: constant variable that stores in a node all the elements that have the class col. All the element retrievable using index numbers. Basically all the cards that we have created

filter: variable that hold the text we typed in the search box

for loop: we go through all cards to search for a match in the card-title and card-text section of each card

title: this variable stores the content of the card-title and card-text section of each card

if clause: it compares the title variable to filter variable and searches for matches. Both strings are converted to lower case we capture both upper and lower case matches. If there is a match (value of indexOf is bigger than 1) we remove the d-none class from the card which means the card is visible. In the no match case (value of indexOf is -1) we add the d-none class to the card which renders it invisible

Since this is javascript we make sure we enclose this snipper in the script tag.

Final words

Javascipt was the last part of our code. That’s it.

I add all the code below in case you want to try it. I promise you it works!

<!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>Document</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>

<body>
    <div class="container">
    
        <div class="row mt-2">
            <div class="col-12 col-md-3 mb-3">
                <input type="text" class="form-control" placeholder="Search cards" aria-label="Search cards"
                    onkeyup="searchFilter()">
    
            </div>
        </div>
    
        <div class="row row-cols-1 row-cols-md-3 g-4">
            <div class="col">
                <div class="card h-100">
                    <img src="https://source.unsplash.com/random?orientation=landscape&sig=123" class="card-img-top"
                        style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                    <div class="card-body  d-flex flex-column">
                        <h5 class="card-title">Random Card One</h5>
                        <p class="card-text">Lorem ipsum dolor sit amet.</p>
                        <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                    </div>
                </div>
            </div>
            <div class="col">
                <div class="card h-100">
                    <img src="https://source.unsplash.com/random??orientation=landscape&sig=234" class="card-img-top"
                        style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                    <div class="card-body  d-flex flex-column">
                        <h5 class="card-title">Random Card Two</h5>
                        <p class="card-text">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Architecto, maxime.
                        </p>
                        <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                    </div>
                </div>
            </div>
            <div class="col">
                <div class="card h-100">
                    <img src="https://source.unsplash.com/random?orientation=landscape&sig=124" class="card-img-top"
                        style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                    <div class="card-body  d-flex flex-column">
                        <h5 class="card-title">Random Card Three</h5>
                        <p class="card-text">Lorem ipsum dolor sit amet consectetur adipisicing elit. Mollitia molestiae
                            suscipit nesciunt. Error, quas nihil.</p>
                        <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                    </div>
                </div>
            </div>
            <div class="col">
                <div class="card h-100">
                    <img src="https://source.unsplash.com/random??orientation=landscape&sig=546" class="card-img-top"
                        style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                    <div class="card-body  d-flex flex-column">
                        <h5 class="card-title">Random Card Four</h5>
                        <p class="card-text">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Laboriosam tenetur
                            quas
                            blanditiis recusandae cumque quidem ex voluptas officiis? Nesciunt, expedita.</p>
                        <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                    </div>
                </div>
            </div>
            <div class="col">
                <div class="card h-100">
                    <img src="https://source.unsplash.com/random?orientation=landscape&sig=634" class="card-img-top"
                        style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                    <div class="card-body  d-flex flex-column">
                        <h5 class="card-title">Random Card Five Double</h5>
                        <p class="card-text">Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad natus voluptate
                            vero,
                            rem dolor praesentium aspernatur, odio, eveniet eligendi nostrum esse repellendus earum ipsum
                            totam.
                        </p>
                        <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                    </div>
                </div>
            </div>
            <div class="col">
                <div class="card h-100">
                    <img src="https://source.unsplash.com/random?orientation=landscape" class="card-img-top"
                        style="width:100% ; height:15vw ; object-fit:cover;" alt="...">
                    <div class="card-body  d-flex flex-column">
                        <h5 class="card-title">Random Card Six double</h5>
                        <p class="card-text">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Tempora consequuntur
                            corrupti repellendus cum ea laborum, dolores perspiciatis numquam atque culpa. A facere, qui
                            provident laudantium rem temporibus aspernatur cumque ratione.</p>
                        <a href="#" class="btn btn-primary btn-dark align-self-end mt-auto stretched-link">Details</a>
                    </div>
                </div>
            </div>
        </div>
    
</div>



    <!-- This is Bootstrap -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous">
    </script>


    <!-- this is javascript-->
    <script>
        var searchFilter = () => {
            const input = document.querySelector(".form-control");
            const cards = document.getElementsByClassName("col");
            console.log(cards[1])
            let filter = input.value
            for (let i = 0; i < cards.length; i++) {
                let title = cards[i].querySelector(".card-body");
                if (title.innerText.toLowerCase().indexOf(filter.toLowerCase()) > -1) {
                    cards[i].classList.remove("d-none")
                } else {
                    cards[i].classList.add("d-none")
                }
            }
        }

    </script>

</body>

</html>

1 Comment

  1. Hi Christos,

    Thank you for this code, it has helped me out of a tight spot! I have a question that I am hoping you can resolve. Is there a way to type in more than one word or description that searches and displays all images with more than one keyword, no matter the order they are typed in, for example, I have an image with 5 keywords i.e. adult, attractive, person, fashion, hair. If I type adult, attractive, person the search works fine, but if I type adult, person no results are displayed.

    Your help would be greatly appreciated.

Leave a Comment

Your email address will not be published. Required fields are marked *

This website uses cookies. By continuing to use this site, you accept our use of cookies.