Building shopping cart with html, tailwindcss and Javascript
A shopping cart is a compulsory section in modern ecommerce web application. Ecommerce web apps processes payment of products. Through shopping cart, the web app is able to:
- Keep track of items selected.
- Get price of each selected item.
- Get quantity of items to be purchased.
- Compute shipping fees
- Compute total amount to be paid for the items.
In summary, shopping cart facilitates the purchase of product or service.
In this tutorial, I'm going to illustrate how to build an interactive shopping cart with html, tailwindcss and javascript.
To follow along with this tutorial, you need to be familiar with the following:
- html
- tailwindcss
- javascript
- dom manipulation
NOTE: This tutorial assumes you already select items from the home page. Now you are in the shopping cart page.
Let's start creating shopping cart.
Create html file and configure tailwindcss
First create index.html
file and configure tailwindcss to index.html
. For installation of tailwindcss in your project, checkout here.
Now lets create index.html
in our project.
Add the head
tag. Inside head
tag, link the following:
- google font to use in the project (fraunces, montserrat).
output.css
file (generated by tailwindcss when project executes)index.js
file (created later)
Below is how head
tag looks
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,700&family=Fraunces:opsz,wght@9..144,500;9..144,700&family=Montserrat:wght@400;500;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="./output.css" />
<script type="module" src="./index.js" defer></script>
<title>cart</title>
</head>
Now let's go to the body
tag. The body
tag contains, the header
tag, section
tag and footer
tag.
The header
tag consist of the cart logo. The section
tag is currently empty (later add cart items). The footer
tag contains cart total price, shipping fee and checkout price and checkout button
.
<body>
<main class="md:p-6 md:pt-10 px-2 pt-6">
<div class="md:flex md:flex-row md:items-center md:justify-between">
<header class=" flex md:flex flex-row gap-x-2 pb-3 items-center">
<img src="./images/bag-2.png" alt="" srcset="" />
<p class="text-darkBlue text-2xl font-bold">Cart</p>
</header>
</div>
<section class="lg:flex lg:flex-row lg:justify-start">
<section class="lg:w-[65%] lg:pr-4">
<div
class="md:w-full border-y-2 py-4 border-lineColor flex flex-row justify-between text-grey font-medium"
>
<div class="md:flex md:w-[45%] md:flex-row md:justify-between ">
<p>PRODUCT</p>
<p>PRICE</p>
</div>
<div class="md:flex md:w-[30%] md:flex-row md:justify-between">
<p>TOTAL</p>
<p>QTY</p>
</div>
</div>
<section id="add-items" class="add-cart-items">
<!-- purchased items -->
</section>
<footer class="bg-totalsGrey p-4 lg:px-4 lg:p-0 lg:w-[35%]">
<div class="total-section">
<p class="total-amount-name">TOTAL AMOUNT IN CART</p>
<p id="add-items-cost" class="total-amount">$</p>
</div>
<div class="total-section">
<p class="total-amount-name">SHIPPING FEE</p>
<p id="shipping-fee" class="total-amount">$</p>
</div>
<div class="total-section">
<p class="total-amount-name">TOTAL AMOUNT</p>
<p id="total-amount-to-pay" class="total-amount">$</p>
</div>
<button id='checkout-btn' class="total-amount mt-4 py-3 w-full active:bg-grey hover:bg-darkBlue bg-blue text-white ">Checkout <span id="checkout-btn-amount">708.85</span></button>
</footer>
</section>
</main>
</body>
NOTE: The colors used in this project are custom colors (not tailwind default colors). These colors are
darkBlue
,totalsGrey
,grey
. For more information about tailwind custom colors check here.
Create two javascript files
The first file is item.js
file. This file has newItem
function. The newItem
function takes an object as a parameter. The object has three properties(image
, name
, price
).
The function has two local variables named createDiv
and itemHtml
. Variable createDiv
stores newly created html div. The itemHtml
stores html code in a string variable.
The innerHtml
property of createDiv
is assign to itemHtml
. The newItem
function returns createDiv
. The function is then exported.
export default function newItem(item){
const createDiv = document.createElement("div");
const itemHtml = `<div class="border-b-2 md:justify-between border-lineColor flex flex-row py-6">
<div class="flex md:w-[45%] md:justify-between flex-col md:flex-row md:items-center w-[60%] ">
<div class="flex flex-row gap-x-2">
<img class="max-w-[7.5rem] h-auto" src="${item.image}" alt="" srcset="" />
<div class="md:pr-6 md:flex md:flex-col md:justify-center" >
<p class="text-lightGrey text-sm md:text-base">Footwear</p>
<p style="white-space:wrap;overflow:hidden;width:100%" class="item-description md:text-lg text-base">
${item.name}
</p>
</div>
</div>
<p class="self-end md:self-center text-xl md:text-2xl font-bold mr-4 md:mr-0">${item.price}</p>
</div>
<div class="w-[40%] md:w-[30%] flex md:flex-row-reverse md:items-center flex-col items-end justify-between">
<p id="total-item-cost" class="text-xl md:text-2xl text-purple font-bold">${item.price}</p>
<div
class="flex flex-row gap-x-2 items-center border-y-[2px] border-lineColor"
>
<button id="decrease" class="increment-btn">-</button>
<p class="px-2">1</p>
<button id="increase" class="increment-btn ">+</button>
</div>
</div>
</div>`;
createDiv.innerHTML = itemHtml;
return createDiv;
}
To the second file now. Create index.js
file. In index.js
file import the newItem
function from item.js
file. Rename the imported function to newShoeItem
.
import newShoeItem from "./item.js";
The index.js
file, contains an array of objects named shoes
. The object has image
, name
and price
properties. The objects displays later as cart selected items.
const shoes = [
{
name:"Nike Air Force 1",
price:110,
image:"https://static.nike.com/a/images/c_limit,w_592,f_auto/t_product_v1/e777c881-5b62-4250-92a6-362967f54cca/air-force-1-07-womens-shoes-b19lqD.png"
},
{
name:"Air Jordan 4 'Black Cat'",
price:240,
image:"https://images.stockx.com/images/Air-Jordan-4-Retro-Black-Cat-2020-Product.jpg?fit=fill&bg=FFFFFF&w=700&h=500&fm=webp&auto=compress&q=90&dpr=2&trim=color&updated_at=1606315877"
},
{
name: "Air Jordan 7 Retro",
price: 200,
image: "https://static.nike.com/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5/bd3da02f-2ddc-4f0c-bb7b-f94c634cc0dd/air-jordan-7-retro-mens-shoes-7Zr804.png",
},
{
name: "Air Jordan 1 Utility",
price: 170,
image: "https://static.nike.com/a/images/c_limit,w_592,f_auto/t_product_v1/956b0723-ef2f-4b49-8982-e2ec37e14f9c/air-jordan-1-utility-mens-shoes.png"
}];
Add DOMContentLoaded
event listener. The event calls addItemToCart
function after loading dom content.
The addItemsToCart
function does the follow:
Get empty
select
tag with idadd-items
Create a loop to get each item object in the array of shoes
Call
newShoeItem
(imported function) passing each shoe as argumentInsert returned html code to empty
select
tag of idadd-items
document.addEventListener("DOMContentLoaded",addItemToCart); function addItemToCart() { const addSelectedShoes = document.getElementById("add-items"); shoes.forEach(shoe=>{ addSelectedShoes.appendChild(shoeItem(shoe)); }) }
Now run
index.html
file in the browser. Your output should resemble the image below
Quantity manipulation
You'll notice the increment(+
) and decrement(-
) buttons are not working when clicked. Let's make the buttons functional in index.js
file.
Increment quantity
Let's start with increment button.To make items quantity increase when +
button is clicked, follow the steps below:
Inside addItemsToCart
function
Get all increment buttons
const incrementButtons = document.querySelectorAll("#increase");
Use
forEach
method to triggerincreaseItems
function on each button.incrementButtons.forEach(increaseItems)
The
increaseItems
function, does the following- Pass in
button
as parameter - Add
click
event listener to thebutton
- Use
event
object to get the current quantity of the items - Increments the current quantity
function increaseItems(button){ button.addEventListener("click", function (e){ e.target.previousElementSibling.textContent++; }) }
Decrement quantity
- Pass in
Making items quantity decrease when clicking -
button.
Inside addItemsToCart
function
- Get all decrement buttons
const decrementButtons = document.querySelectorAll("#decrease");
Use
forEach
method to triggerdecreaseItems
function on each button.decrementButtons.forEach(decreaseItems)
The
decreaseItems
function does the following:- Pass in
button
as parameter - Add
click
event listener to thebutton
- Use
event
object to get current item quantity - Decrement current quantity, if current quantity is greater than 1
Now, we are able to increment and decrement the quantity whenfunction decreaseItems(button) { button.addEventListener("click", function (e) { let currentQuantity = e.target.nextElementSibling.textContent; if(currentQuantity > 1){ e.target.nextElementSibling.textContent--; } }); }
+
button and-
button are clicked as shown below. We are able to increase and decrease the quantity. But the quantity amount is still constant.
- Pass in
Updating total item price
We need to multiply item price with quantity to get total item price
Create totalItemPrice
function. The function will take in two parameters element
and siblingPostion
. The totalItemPrice
function does the following:
Use
element
parameter(clicked button) to get item price by dom traverseUse
siblingPosition
parameter to get item quantityMultiply item price with item quantity to get total item price
Use
element
to get text content of total item price and update total item pricefunction totalItemPrice(element,siblingPosition){ let itemPrice = element.parentElement.parentElement.previousElementSibling.children[1].textContent.slice(1); let itemQuantity = siblingPosition.textContent; let totalItemPrice = itemPrice * itemQuantity; element.parentElement.previousElementSibling.textContent = `$${totalItemPrice}`; }
Now we need to call
totalItemPrice
function insidedecreaseItem
andincreaseItem
function. This will make item total price update everytime increment and decrement button is clicked.
We'll call totalItemPrice
function inside click event function of increaseItem
and decreaseItem
function.
We'll use the event
object to get the arguments in totalItemPrice
.
In increaseItem
the arguments used in event function are e.target
and e.target.previousElementSibling
.
const previousSibling = e.target.previusElementSibling;
totalItemPrice(e.target,previousSibling);
In decreaseItem
the arguments used in event function are e.target
and e.target.nextElementSibling
.
const nextSibling = e.target.nextElementSibling;
totalItemPrice(e.target,previousSibling);
The e.target
is the button clicked. The e.target.previousElementSibling
and e.target.nextElementSibling
gets item quantity
Total item price updates when +
and -
buttons are clicked.
Now we need to sum up item total price.
Compute cart Total price, shipping fee and checkout price
A cart need to sum up total item price, compute shipping fees and calculate the checkout price of the items. We're going to create calculateTotals
function. The function returns an array.
calculateTotals
function does the following:
- Declare
cartTotalPrice
variable and initializecartTotalPrice
to 0. - Get each item total price and add them to
cartTotalPrice
. - Declare
shippingFee
variable and initialize it to 7% ofcartTotalPrice
. - Declare
totalCashToPay
variable and initialize it to sum ofcartTotalPrice
andshippingFee
. - Returns an array consisting of three variables;
cartTotalPrice
,shippingFee
andtotalCashToPay
.function calculateTotals() { let cartTotalPrice = 0; const getItemPrices = document.querySelectorAll("#total-item-cost"); getItemPrices.forEach(itemPrice =>{ cartTotalPrice += Number(itemPrice.textContent.slice(1)); }) const shippingFee = (cartTotalPrice*7/100); const totalCashToPay = cartTotalPrice + shippingFee; return [cartTotalPrice.toFixed(2), shippingFee.toFixed(2), totalCashToPay.toFixed(2)] }
Updating cart Total price, shipping fee and checkout price on corresponding elements
We need to update the UI with computed values. Everytime the user decrement or increment quantity, the UI needs to show real time values.
We create updateTotals
function which takes in two parameters. The parameters are elementId
and value
. It then gets the element of the id and update the element text content with the value
.
function updateTotals(elementId,value){
const element = document.querySelector(elementId);
element.textContent = value;
}
We'll call calculateTotals
and updateTotals
function inside the totalItemPrice
function. This will make updates when either increment or decrement button is clicked.
The calculateTotals
function will return an array. Then destructure the array to get three independent value.
const [totalPrice,shippingFee,checkoutPrice] = calculateTotals();
Now we call the updateTotals
function to change the initial value of the elements to current value.
- Update content of element with id
add-items-cost
tototalPrice
value. - Update content of element with id
shipping-fee
toshippingFee
value. - Update content of element with id
total-amount-to-pay
tocheckoutPrice
value. - Update checkout button to read
checkoutPrice
.
Finally your shopping cat should be responsive and resemble the image below. Now the shopping cart is responsive and manipulable. In summary the shopping cart is able to:updateTotals("#add-items-cost",`$${totalPrice}`); updateTotals("#shipping-fee",`$${shippingFee}`); updateTotals("#total-amount-to-pay",`$${checkoutPrice}`); updateTotals("#checkout-btn",`Checkout $${checkoutPrice}`);
- Increase and decrease item quantity
- Compute item total price
- Sum item total price
- Compute shipping fee
- Compute total checkout price