Dropdown Search Filter in Javascript

In a previous post we implemented a search box where users dynamically would type keywords to filter the Boostrap card gallery. In this post we will complement the page with an additional dropdown search filter in javascript to provide more filtering options to users. Here is what you are going to see once we finish

Dropdown Filter with Searchbox

Let’s see how we implement that additional dropdown filter in Javascript. Obviously you can add more but for the sake of simplicity we will implement only one here.

Positioning of the dropdown filter

We will add the additional filter next to the searchbox in the same line. Bootstrap makes it super easy. Here is the code along with a brief explanation

        <div class="row mt-2">
            <div class="col-12 mb-3 col-md-6">
                <select class="form-select" id="filterByColor" onchange="searchFilter()">
                    <option value="" selected>Filter by Color</option>
                    <option value="green">Green</option>
                    <option value="blue">Blue</option>
                    <option value="yellow">Yellow</option>
                </select>
            </div>
            <div class="col-12 col-md-6 mb-3">
                <input type="text" class="form-control" placeholder="Search cards" aria-label="Search cards" onkeyup="searchFilter()">
        
            </div>
        </div>

div class=”col-12 mb-3 col-md-6″ : In smartphone screen (col-12) the filter will take one line by itself. Same for the Searchbox. In a medium screen and above (col-md-6) the filter will take half the space and the Searchbox the other half. Remember the default Bootstrap grid is split in 12 columns so 6 is half of the screen space. If you would like to add another filter and split the row into 3 you would have written col-md-4 in each div box. You get the idea right ?

id=”filterByColor” : we add an id so that we can refer to this part of the HTML code in javascript

onchange=”searchFilter()”: we call the searchFilter() function once the value changes in the dropdown filter. This function will be defined in javascript and it will automatically filter the Bootstrap cards based on our selection

<option>: this contains our options from the dropdown menu also the values that will represent each selection. By selecting an option its associated value (green, blue, yellow or null if we don’t select a color) will be stored in a javascript variable for use in our filter

The rest of the code is pretty much the same as we explained in the previous post.

Bootstrap cards

There is no significant change in the HTML code for this section. Instead of populating random cards from Unsplash I selected specific ones so that we can filter them by color.

Here’s the code

       <div class="row row-cols-1 row-cols-md-3 g-4 gridCards">
            <div class="col green">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1573952106639-694daec2b88a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80" 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 blue">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1601436155198-2ebfea8117b0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80" 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 yellow">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1521913626209-0fbf68f4c4b1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80" 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 green">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1574750851163-cabd9458f3b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=327&q=80" 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 yellow">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1602108987428-4768d7c7ecbe?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" 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 green">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1601370690183-1c7796ecec61?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80" 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>

There is also one important addition. Did you spot it ?

In each card in the <div class=”col“> I added the color of the card manually. For example in the first card I added the green class <div class=”col green”>. As you might have guessed every image has its own color class and the filter will compare our dropdown selection against the class of each image.

How ? Check the next section where we implement the actual filter

Filtering

Finally we are going to create a new filter based on our selection from the dropdown menu and also integrate the Searchbox from our previous post

Here’s the code along with some explanation of various parts.

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

searchFilter: This function is called when we select a value from the dropdown menu or when we type something in the Searchbox (see code above)

selectedColor = document.getElementById(“filterByColor”).value; : we get the value of the element with id filterByColor (the dropdown menu) and store it in the selectedColor variable. So this value is either green, blue, yellow or null.

const input = document.querySelector(“.form-control”); : we take the element with class form-control (the Searchbox) and store it in the input variable

let filter = input.value; : we take value of the input above (what we typed in the Searchbox and we store it in the textBox variable

conditional if section: we iterate over each card and we check the value of its class contains against the value of the variable selectedColor AND if the text in the Searchbox matches the title or text in the card (if there is a match the indexOf will be greater than -1). If the end result is True, we remove the d-none class from the card which in bootstrap renders the card visible. In the opposite case, we add the d-none class in the card and that makes it invisible.

Hint: if something is not clear (believe me it takes me a lot of time to understand part of the code myself) don’t hesitate to use console.log. One way to use it is to get the value of each variable and verify everything is correct. For example if you want to get the value of the selectedColor variable, after the line where we define it just type

console.log(selectedColor)

Its value will be displayed in the console when you play with the dropdown menu

Code

Here is all the code in one piece. Enjoy!

<!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 mb-3 col-md-6">
                <select class="form-select" id="filterByColor" onchange="searchFilter()">
                    <option value="" selected>Filter by Color</option>
                    <option value="green">Green</option>
                    <option value="blue">Blue</option>
                    <option value="yellow">Yellow</option>
                </select>
            </div>
            <div class="col-12 col-md-6 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 gridCards">
            <div class="col green">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1573952106639-694daec2b88a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80" 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 blue">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1601436155198-2ebfea8117b0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80" 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 yellow">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1521913626209-0fbf68f4c4b1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80" 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 green">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1574750851163-cabd9458f3b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=327&q=80" 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 yellow">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1602108987428-4768d7c7ecbe?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" 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 green">
                <div class="card h-100">
                    <img src="https://images.unsplash.com/photo-1601370690183-1c7796ecec61?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80" 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 = () => {
            let selectedColor = document.getElementById("filterByColor").value;
            console.log(selectedColor);
            const input = document.querySelector(".form-control");
            const cards = document.getElementsByClassName("col");
            console.log(cards[1])
            let textBox = input.value;
            for (let i = 0; i < cards.length; i++) {
                let title = cards[i].querySelector(".card-body");
                if ((cards[i].classList.contains(selectedColor) || selectedColor=="") && title.innerText.toLowerCase().indexOf(textBox.toLowerCase()) > -1) {
                    cards[i].classList.remove("d-none");
                } else {
                    cards[i].classList.add("d-none");
                }
            }
        }
    </script>

</body>

</html>

3 Comments

  1. Amazing script, thank you! Two issues: is it normal that I can’t use the search field unless I first select a color. I think it’s not and I think it’s related to the second issue Im having. When I select a color the cards filter as expected, but when I reselect the default “Filter by Color” the hidden cards don’t reappear and the console raises the following error:
    1417 Uncaught TypeError: Cannot read properties of null (reading ‘innerText’)
    at searchFilter
    at HTMLSelectElement.onchange

    1. Γεια σου Alex! No this is not normal. I just copied the whole code from the post to test it again and I don’t have the issue you describe. That makes me think your issue is specific to your environment. Can you use a different browser ? Let me know how it goes

Comments are closed.

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