Building shopping cart with html, tailwindcss and Javascript
Tags: webdev, tutorial, javascript, showdev
Published: 2023-09-16 18:04:34

[](url)
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](https://tailwindcss.com/docs/installation).
Now 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

```html
<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 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`.

```html
<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](https://tailwindcss.com/docs/customizing-colors).

## 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.

```js
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;
}
```
Create `index.js` file. In `index.js` file import the `newItem` function from `item.js` file. Rename the imported function to `newShoeItem`.
```js
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.
```js
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:

1. Get empty `select` tag with id `add-items`

2. Create a loop to get each item object in the array of shoes
3. Call `newShoeItem`(_imported function_) passing each shoe as argument

4. Insert returned html code to empty `select` tag of id `add-items`

    ```js
    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

![Initial stage of shopping cart](https://bryondickers.github.io/technical-w/images/initial-cart.png)

## Quantity manipulation
You'll notice the increment(`+`) and decrement(`-`) buttons are not working when clicked. You should make the buttons functional in `index.js` file.

### Increment quantity
Start with increment button.To make items quantity increase when `+` button is clicked, follow the steps below:

Inside `addItemsToCart` function

1. Get all increment buttons 
    ```js
    const incrementButtons = document.querySelectorAll("#increase");
    ```

2. Use `forEach` method to trigger `increaseItems` function on each button.
    ```js
    incrementButtons.forEach(increaseItems)
    ```

3. The `increaseItems` function, does the following

    1. Pass in `button` as parameter
    2. Add `click` event listener to the `button`
    3. Use `event` object to get the current quantity of the items
    4. Increments the current quantity
        ```js
        function increaseItems(button){
        button.addEventListener("click", function (e){
        e.target.previousElementSibling.textContent++;
         })
        }
        ```
### Decrement quantity   

Make items quantity decrease when clicking `-` button.

Inside `addItemsToCart` function

1. Get all decrement buttons 
    ```js
    const decrementButtons = document.querySelectorAll("#decrease");
    ```
2. Use `forEach` method to trigger `decreaseItems` function on each button.
    ```js
    decrementButtons.forEach(decreaseItems)
    ```

3. The `decreaseItems` function does the following:
    1. Pass in `button` as parameter
    2. Add `click` event listener to the `button`
    3. Use `event` object to get current item quantity
    4. Decrement current quantity, if current quantity is greater than 1
        ```js
        function decreaseItems(button) {
        button.addEventListener("click", function (e) {
        let currentQuantity = e.target.nextElementSibling.textContent;
        if(currentQuantity > 1){
        e.target.nextElementSibling.textContent--;
            }
          });
        }
        ```
Now, you are able to increment and decrement the quantity when `+` button and `-` button are clicked as shown below.
![increment and decrement items quantity in shopping cart](https://bryondickers.github.io/technical-w/images/increment-cart.png)
You are able to increase and decrease the quantity. But the quantity amount is still constant.

## Updating total item price
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:

1. Use `element` parameter(_clicked button_) to get item price by [dom traverse](https://www.easeout.co/blog/2020-12-28-traversing-the-dom/)

2. Use `siblingPosition` parameter to get item quantity

3. Multiply item price with item quantity to get total item price
4. Use `element` to get text content of total item price and update total item price

    ```js
    function 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 you need to call `totalItemPrice` function inside `decreaseItem` and `increaseItem` function. This will make item total price update everytime increment and decrement button is clicked.

Call `totalItemPrice` function inside click event function of `increaseItem` and `decreaseItem` function.

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`.
```js
const previousSibling = e.target.previusElementSibling;
totalItemPrice(e.target,previousSibling);
```

In `decreaseItem` the arguments used in event function are `e.target` and `e.target.nextElementSibling`. 
```js
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.
![update item total price when increase or decrease button is pressed](https://bryondickers.github.io/technical-w/images/total-item-price.png)
Now 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. You are going to create `calculateTotals` function. The function returns an array.

The `calculateTotals` function does the following:

1. Declare `cartTotalPrice` variable and initialize `cartTotalPrice` to 0.
2. Get each item total price and add them to `cartTotalPrice`. 
3. Declare `shippingFee` variable and initialize it to 7% of `cartTotalPrice`.
4. Declare `totalCashToPay` variable and initialize it to sum of `cartTotalPrice` and `shippingFee`.
5. Returns an array consisting of three variables; `cartTotalPrice`, `shippingFee` and `totalCashToPay`.
    ```js
   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
You need to update the UI with computed values. Everytime the user decrement or increment quantity, the UI needs to show real time values. 

Create `updateTotals` function which takes in two parameters. The parameters are `elementId` and `value`. The function gets the element of the id and update the element text content with the `value`.

```js
function updateTotals(elementId,value){
  const element = document.querySelector(elementId);
  element.textContent = value;
}
```
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) the array to get three independent value. 

```js
const [totalPrice,shippingFee,checkoutPrice] = calculateTotals();
```
Now call the `updateTotals` function to change the initial value of the elements to current value.

1. Update content of element with id `add-items-cost` to `totalPrice` value.
2. Update content of element with id `shipping-fee` to `shippingFee` value.
3. Update content of element with id `total-amount-to-pay` to `checkoutPrice` value.
4. Update checkout button to read `checkoutPrice`.
    ```js
    updateTotals("#add-items-cost",`$${totalPrice}`);
    updateTotals("#shipping-fee",`$${shippingFee}`);
    updateTotals("#total-amount-to-pay",`$${checkoutPrice}`);
    updateTotals("#checkout-btn",`Checkout $${checkoutPrice}`);
    ```
Finally your shopping cat should be responsive and resemble the image below.
![Final shopping cart image ](https://bryondickers.github.io/technical-w/images/checkout-cart.png)
Now the shopping cart is responsive and manipulable. In summary the shopping cart is able to:
  + Increase and decrease item quantity
  + Compute item total price
  + Sum item total price
  + Compute shipping fee
  + Compute total checkout price