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
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
Creating the Searchbox
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.
Create the Bootstrap Gallery
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>
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.