I observed that in eCommerce websites filtering products based on certain filters or user inputs is a super common thing.
In this little tutorial, I'll be trying to layout the mechanics of filtering data from a state based on the search input.
Of course you can go all out and add all the fancy toggle filters, advanced search options and whatnot. But the concept of filtering stays the same, more or less.
Hope you enjoy!
Sketching out a product state
Let's try to make a close to real ecommerce product list. The aim here is to use "tags", "title", "category" fields to look for the products. The tag filed contains few descriptions of what the product is. Just like Instagram #hashtags
{
id: 1,
title: "Check Textured Coat",
category: "Coat",
price: "175.4",
tags: "coat check textured camel brown long sleeves buttoned cuffs",
},
{
id: 2,
title: "Contrast Check Coat",
category: "Coat",
price: "155.4",
tags: "coat camel black grey marl lapel collar hip flap pockets",
},
{
id: 3,
title: "White Coat",
category: "Coat",
price: "125.4",
tags: "coat camel white short sleeves double-breasted button",
},
{
id: 4,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain purple long baggy hood",
},
{
id: 5,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain black long baggy hood",
},
{
id: 6,
title: "Basic short Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain gray grey short hood",
},
]
SearchBarSection.js up-until now!
// SearchBarSection.js
import React, {useState} from "react";
const SearchBarSection = () => {
const [products, setProducts] = useState([
{
id: 1,
title: "Check Textured Coat",
category: "Coat",
price: "175.4",
tags: "coat check textured camel brown long sleeves buttoned cuffs",
},
{
id: 2,
title: "Contrast Check Coat",
category: "Coat",
price: "155.4",
tags: "coat camel black grey marl lapel collar hip flap pockets",
},
{
id: 3,
title: "White Coat",
category: "Coat",
price: "125.4",
tags: "coat camel white short sleeves double-breasted button",
},
{
id: 4,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain purple long baggy hood",
},
{
id: 5,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain black long baggy hood",
},
{
id: 6,
title: "Basic short Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain gray grey short hood",
},
]);
return <div></div>;
};
export default SearchBarSection;
UI Component
We are just looking to setup a search bar and a display section. So lets get through with a basic UI first.
But before we get into it, might as well import this in App.js and have a look at our marvelous (laughs a lot of em'!) design on the browser
App.js
// App.js
import SearchBarSection from "./Projects/SearchBarSection/SearchBarSection";
function App() {
return (
<div>
<SearchBarSection />
</div>
);
}
export default App;
Search Bar
Just the UI of the search bar. We'll implement the input functionalities in the later section.
return (
<div className="searchBarSection">
<div class="searchBar">
<input className="input" />
<button className="button">
<svg
className="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</button>
</div>
</div>
);
SearchBarSection.js up-until now!
// SearchBarSection.js
import React, {useState} from "react";
import "./SearchBarSection.css";
const SearchBarSection = () => {
const [products, setProducts] = useState([
{
id: 1,
title: "Check Textured Coat",
category: "Coat",
price: "175.4",
tags: "coat check textured camel brown long sleeves buttoned cuffs",
},
{
id: 2,
title: "Contrast Check Coat",
category: "Coat",
price: "155.4",
tags: "coat camel black grey marl lapel collar hip flap pockets",
},
{
id: 3,
title: "White Coat",
category: "Coat",
price: "125.4",
tags: "coat camel white short sleeves double-breasted button",
},
{
id: 4,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain purple long baggy hood",
},
{
id: 5,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain black long baggy hood",
},
{
id: 6,
title: "Basic short Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain gray grey short hood",
},
]);
return (
<div className="searchBarSection">
<div class="searchBar">
<input className="input" />
<button className="button">
<svg
className="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</button>
</div>
</div>
);
};
export default SearchBarSection;
/* SearchBarSection.css */
.searchBarSection {
margin: 100px auto;
display: flex;
flex-direction: column;
align-items: center;
}
.searchBar {
display: flex;
align-items: center;
background-color: white;
border: 1px solid;
border-radius: 20px;
}
.input {
width: 250px;
border: none;
border-radius: 20px;
}
.button {
background-color: transparent;
border: none;
width: 25px;
border-radius: 20px;
}
Product Display
I don't want to focus much on UI enhancements in this blog. This is more on the technical implementation side.
So we'll be displaying the products WITHOUT IMAGES.
<div className="display">
{products.map((product) => (
<div className="product">
<h6>{product.category}</h6>
<h3>{product.title}</h3>
<h5>{product.price}</h5>
</div>
))}
</div>
We are not yet filtering the products based on search input and hence we see the whole list.
We'll do that in the next section.
SearchBarSection.js up until now!
import React, {useState} from "react";
import "./SearchBarSection.css";
const SearchBarSection = () => {
const [products, setProducts] = useState([
{
id: 1,
title: "Check Textured Coat",
category: "Coat",
price: "175.4",
tags: "coat check textured camel brown long sleeves buttoned cuffs",
},
{
id: 2,
title: "Contrast Check Coat",
category: "Coat",
price: "155.4",
tags: "coat camel black grey marl lapel collar hip flap pockets",
},
{
id: 3,
title: "White Coat",
category: "Coat",
price: "125.4",
tags: "coat camel white short sleeves double-breasted button",
},
{
id: 4,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain purple long baggy hood",
},
{
id: 5,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain black long baggy hood",
},
{
id: 6,
title: "Basic short Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain gray grey short hood",
},
]);
return (
<div className="searchBarSection">
<div class="searchBar">
<input className="input" />
<button className="button">
<svg
className="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</button>
</div>
<div className="display">
{products.map((product) => (
<div className="product">
<h6>{product.category}</h6>
<h3>{product.title}</h3>
<h5>{product.price}</h5>
</div>
))}
</div>
</div>
);
};
export default SearchBarSection;
Adding in some CSS.
.display {
display: flex;
flex-wrap: wrap;
}
.product {
margin: 20px;
width: 200px;
padding: 20px;
border-radius: 20px;
background-color: #f9d5d3;
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
}
SearchBarSection.css up until now!
/* SearchBarSection.css */
.searchBarSection {
margin: 100px auto;
display: flex;
flex-direction: column;
align-items: center;
}
.searchBar {
display: flex;
align-items: center;
background-color: white;
border: 1px solid;
border-radius: 20px;
}
.input {
width: 250px;
border: none;
border-radius: 20px;
}
.button {
background-color: transparent;
border: none;
width: 25px;
border-radius: 20px;
}
.display {
display: flex;
flex-wrap: wrap;
}
.product {
margin: 20px;
width: 200px;
padding: 20px;
border-radius: 20px;
background-color: #f9d5d3;
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
}
Setting up search functionality
The first thing we need to setup is a state to store the search input.
const [search, setSearch] = useState("");
Now let's try to filter out the products based on this search state.
Here we are searching the string stored in the search state within tags, title and category string.
You can see some examples on Array.prototype.includes()
const filteredProducts = products.filter((product) => {
if (
product.tags.toLowerCase().includes(search) ||
product.title.toLowerCase().includes(search) ||
product.category.toLowerCase().includes(search)
) {
return product;
}
});
Perfect! We are almost done. Let's just quickly setup the onChange attribute on the input to set the "search" state on each character input.
<input
className="input"
onChange={(e) => {
setSearch(e.target.value.toLowerCase());
}}
/>
Last little tweak and it's done! Just replace the "product" in the "display" div with "filteredProducts"
<div className="display">
{filteredProducts.map((product) => (
<div className="product">
<h6>{product.category}</h6>
<h3>{product.title}</h3>
<h5>{product.price}</h5>
</div>
))}
</div>
SearchBarSection.js final!
import React, {useState} from "react";
import "./SearchBarSection.css";
const SearchBarSection = () => {
const [products, setProducts] = useState([
{
id: 1,
title: "Check Textured Coat",
category: "Coat",
price: "175.4",
tags: "coat check textured camel brown long sleeves buttoned cuffs",
},
{
id: 2,
title: "Contrast Check Coat",
category: "Coat",
price: "155.4",
tags: "coat camel black grey marl lapel collar hip flap pockets",
},
{
id: 3,
title: "White Coat",
category: "Coat",
price: "125.4",
tags: "coat camel white short sleeves double-breasted button",
},
{
id: 4,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain purple long baggy hood",
},
{
id: 5,
title: "Basic Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain black long baggy hood",
},
{
id: 6,
title: "Basic short Hoodie",
category: "Hoodies / SweatShirts",
price: "55.4",
tags: "hoodie solid plain gray grey short hood",
},
]);
const [search, setSearch] = useState("");
const filteredProducts = products.filter((product) => {
if (
product.tags.toLowerCase().includes(search) ||
product.title.toLowerCase().includes(search) ||
product.category.toLowerCase().includes(search)
) {
return product;
}
});
return (
<div className="searchBarSection">
<div class="searchBar">
<input
className="input"
onChange={(e) => {
setSearch(e.target.value.toLowerCase());
}}
/>
<button className="button">
<svg
className="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</button>
</div>
<div className="display">
{filteredProducts.map((product) => (
<div className="product">
<h6>{product.category}</h6>
<h3>{product.title}</h3>
<h5>{product.price}</h5>
</div>
))}
</div>
</div>
);
};
export default SearchBarSection;
SearchBarSection.css final!
/* SearchBarSection.css */
.searchBarSection {
margin: 100px auto;
display: flex;
flex-direction: column;
align-items: center;
}
.searchBar {
display: flex;
align-items: center;
background-color: white;
border: 1px solid;
border-radius: 20px;
}
.input {
width: 250px;
border: none;
border-radius: 20px;
}
.button {
background-color: transparent;
border: none;
width: 25px;
border-radius: 20px;
}
.display {
display: flex;
flex-wrap: wrap;
}
.product {
margin: 20px;
width: 200px;
padding: 20px;
border-radius: 20px;
background-color: #f9d5d3;
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
}
Oh oh! I almost forgot.
App.js
// App.js
import SearchBarSection from "./Projects/SearchBarSection/SearchBarSection";
function App() {
return (
<div>
<SearchBarSection />
</div>
);
}
export default App;
Top comments (2)
Honestly, searching in constant array will not be a production case 😉 In real world you have to use ElasticSearch or something like Algolia
THAT IS ABSOLUTELY TRUE!!
I would personally prefer Algolia for professional projects, because of two reasons:
That being said, when I was learning the basics of react. I always used to use filter function for any kind of search-based functionality.
So I thought it might help!😁