Let's create a product page with filters together
using HTML, CSS and Javascript for beginners
This tutorial will walk you through how to make a product page that filters through the different products.
You can reuse this to make any page that needs to filter through products such as an e-commerce website or a restaurant menu.
Key concepts covered
- arrays
- objects
- forEach()
- DOMContentLoaded
- map, reduce, and filter
- innerHTML
- includes method
First Thing First, we set up the project
- create a folder
- create an HTML file (index.html)
- create a CSS file (styles.css)
- create a Javascript file (app.js)
- create an image folder with our products' images
Starting with the skeleton (HTML)
Set up:
in the HTML file (for me it's index.html), include the CSS and javascript files.
<!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>Products</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<section class="products"> </section>
<script src="app.js"></script>
</body>
</html>
Now we can start:
Title:
<div class="title">
<h1>Our Products</h1>
<hr />
</div>
Main Container:
<section class="products">
<!-- title -- >
<div class="title">
<h1>Our Products</h1>
<hr />
</div>
<!-- Filter buttons -- >
<!-- products -- >
<div class="section-center">
<!-- start product -- >
<!-- end product -- >
</div>
</section>
Product:
<!-- start product-->
<article class="product">
<img src="./images/Leather.jpg" alt="Leather Heels" class="photo" />
<div class="product-info">
<header>
<h4>Brown Leather Heels</h4>
<h4 class="price">$66.55</h4>
</header>
<p class="product-text">
Anim culpa cupidatat consectetur qui proident sint sunt dolor esse
tempor eu ullamco nulla. Excepteur exercitation laborum eu
laborum.
</p>
</div>
</article>
<!-- end product-->
Filter Buttons:
<!-- Filter buttons-->
<div class="btn-container">
<div class="filter-btn" type="button">All</div>
<div class="filter-btn" type="button">Sneakers</div>
<div class="filter-btn" type="button">Heels</div>
<div class="filter-btn" type="button">Boots</div>
</div>
Let's make it pretty (CSS)
Set up:
choose the colour palette: I prefer using Coolors
choose fonts: I prefer using Google Fonts
@import url('https://fonts.googleapis.com/css2?family=Oswald&display=swap');
:root {
--pacific-blue: #00b2caff;
--yale-blue: #1d4e89ff;
--cameo-pink: #efbbcc;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 100%;
height: 100vh;
font-family: 'Oswald', sans-serif;
}
section.products{
padding: 2.5rem 0;
}
Title :
.title{
margin: auto;
width: 115px;
color: var(--yale-blue);
padding-bottom: 1.5rem;
}
hr{
border-radius: 5px;
background-color: var(--pacific-blue);
border: 1px solid var(--pacific-blue);
}
Main Container:
.section-center{
width: 90vw;
margin: 0 auto;
max-width: 1170px;
display: grid;
gap: 3rem 2rem;
justify-items: center;
}
Product:
.photo{
object-fit: cover;
height: 160px;
border: 0.25rem solid var(--pacific-blue);
border-radius: 0.5rem;
max-width: 110px;
}
.product {
display: flex;
justify-content: space-evenly;
color: var(--yale-blue);
max-width: 25rem;
gap: 1rem 2rem;
}
.product-info{
display: flex;
flex-direction: column;
justify-content: space-evenly;
}
.product header{
display: flex;
justify-content: space-between;
}
.price {
color: var(--pacific-blue);
}
.product-text {
margin-bottom: 0;
text-align: justify;
}
Filter Buttons:
.btn-container {
margin-bottom: 2rem;
display: flex;
justify-content: center;
}
.filter-btn {
background: transparent;
border: 0.25rem solid var(--cameo-pink);
font-weight: bold;
margin: 0 0.5rem;
border-radius: 0.5rem;
padding: 0.5rem;
color:var(--yale-blue);
cursor: pointer;
transition: all 0.3s linear;
}
.filter-btn:hover {
background: var(--yale-blue);
color: var(--cameo-pink);
}
Media Queries:
@media screen and (min-width: 1200px) {
.section-center {
width: 95vw;
grid-template-columns: 1fr 1fr;
}
.product {
grid-template-columns: 225px 1fr;
gap: 0 1.25rem;
max-width: 40rem;
}
}
Make it dynamic (Javascript)
Include products:
const products = [
{
id: 1,
title: "Nike airforce 1",
category: "Sneakers",
price: 66.99,
image: "./images/airforce.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 2,
title: "Brown Leather Heels",
category: "Heels",
price: 66.55,
image: "./images/Leather.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 3,
title: "Brown Male Boots",
category: "Boots",
price: 55.99,
image: "./images/Brown.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 4,
title: "Red Converse All Star",
category: "Sneakers",
price: 55.99,
image: "./images/Converse.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 5,
title: "Weeding Heels",
category: "Heels",
price: 55.99,
image: "./images/Weeding.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 6,
title: "Male Boots",
category: "Boots",
price: 72.55,
image: "./images/Male.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 7,
title: "Floral Heels",
category: "Heels",
price: 42.99,
image: "./images/Floral.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 8,
title: "Jordan 1 Retro",
category: "Sneakers",
price: 76.99,
image: "./images/Jordan.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
{
id: 9,
title: "Midwest Trekking",
category: "Boots",
price: 72.99,
image: "./images/Midwest.jpg",
description: `Anim culpa cupidatat consectetur qui proident sint sunt dolor esse tempor eu ullamco nulla. Excepteur exercitation laborum eu laborum.`,
},
];
Main container:
// get parent element
const section center = document.querySelector(".section-center");
const btnContainer = document.querySelector(".btn-container");
// load items
window.addEventListener("DOMContentLoaded", function () {
displayProductsItems(products);
displayProductsButtons();
});
Product:
function displayProductsItems(productsItems) {
let displayProducts = productsItems.map(function (item) {
return `<article class="product">
<img src= ${item.image} alt=${item.title} class="photo" />
<div class="product-info">
<header>
<h4>${item.title}</h4>
<h4 class="price">$${item.price}</h4>
</header>
<hr />
<p class="product-text">
${item.description}
</p>
</div>
</article>`;
});
displayProducts = displayProducts.join("");
sectionCenter.innerHTML = displayProducts;
}
Filter Buttons:
function displayProductsButtons() {
const categories = products.reduce(
function (values, item) {
if (!values.includes(item.category)) {
values.push(item.category);
}
return values;
},
["All"]
);
const categoryBtns = categories
.map(function (category) {
return `<div class="filter-btn" type="button" data-id=${category}>${category}</div>`;
})
.join("");
btnContainer.innerHTML = categoryBtns;
const filterBtns = btnContainer.querySelectorAll(".filter-btn");
filterBtns.forEach(function (btn) {
btn.addEventListener("click", function (e) {
const category = e.currentTarget.dataset.id;
const productsCategory = products.filter(function (productsItems) {
if (productsItems.category === category) {
return productsItems;
}
});
if (category === "All") {
displayProductsItems(products);
} else {
displayProductsItems(productsCategory);
}
});
});
}
Conclusion:
To see the completed project: Project
To see the final code: Code
Thank you for your time. I hope you found it useful. ❤️
If you enjoyed this article and want to be the first to know when I post a new one, you can follow me on Twitter @habibawael02 or here @HabibaWael