March 21, 2023March 24, 2023 How to Create a Shopping Cart in Plain Javascript Shopping carts are one of the main features of any ecommerce site. When a customer browses your ecommerce site you want them to easily add products and see the products in their cart. Storing product data in a session or database is important so the customers can see their selected products when clicking to new a page or refreshing. But in this article we will start very simple and use javascript so we only need the front end to see the functionality. We’ll start with the nav bar we made from the last post. Adding a Shopping Cart IconCreating a Product SectionShopping Cart Functionality with Javascript Adding a Shopping Cart Icon Now lets get a shopping cart icon from a site with free vectors like svgrepo.com. Download the icon you like. Make an images folder in your root directory. Move the cart icon to your images folder and name it ‘cart.svg’. Now lets place it in our nav bar to the right of our links. Here’s the HTML code. <!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 rel="stylesheet" href="tmp.css"> </head> <body> <nav class="top-nav"> <div class="logo-container"> Logo Here </div> <ul class="nav-links"> <li class="nav-link"><a href="#">Home</a></li> <li class="nav-link"><a href="#">Shop</a></li> <li class="nav-link"><a href="#">About</a></li> <li class="nav-link"><a href="#">Contact</a></li> <div class="nav-icon-wrapper"> <img src="images/cart.svg" alt="" srcset=""> <span class="nav-cart-count">10</span> </div> </ul> </nav> </body> </html> Inside we also have the nav-cart-count span which we will work on so it hides when there is no products in the cart. And then show it with the correct amount of products. For now we’ll put a random number inside to make sure it looks good. Next we will style the nav cart icon and the quantity. When positioning the quantity element we will give the parent a position of relative so when we give the child a position of absolute it will remain inside the parent. .nav-icon-wrapper { position: relative; } .nav-icon-wrapper img { width: 30px; height: 30px; } .nav-cart-count { background-color: rgb(169, 67, 67); width: 22px; height: 22px; color: white; position: absolute; top: -8px; left: 15px; align-items: center; justify-content: center; border-radius: 50%; } We give the background color of the quantity something that stands out with our color scheme. And then use the top and left properties to position it precisely on the corner of the cart image. Once it looks pretty enough we want to hide the quantity until there are products in the cart. Hide it with… display: none; Creating a Product Section Now what good is a cart without products to add? Lets add our product section with a header. Insert this product section right after the nav bar. <section class="product-section"> <h2 class="products-heading">Dev Starter Kit</h2> <div class="products-wrapper"> </div> </section> At this point we should have a theme of our shop. Since we are developing lets make a ecommerce site where developers can buy stuff they might need. We’ll give the product section a heading “Dev Starter Kit”. And we might as well rename the logo container in the nav bar to Dev Shop. <nav class="top-nav"> <div class="logo-container"> Dev Shop </div> Now we can create our product elements to display inside the products wrapper. This is where we’ll show the product data which includes the name, image, price, and description. We will need images so you can go to a stock photo site such as unsplash.com and search for products you want to add. I am going to add a laptop for my dev starter kit. Let’s create a product card so that the image is at the top, the product info in the middle, and an “Add to Cart” button at the bottom with the product id number. <div class="product-card"> <div class="product-img"> <img src="images/laptop.png" alt="laptop" title="laptop"> </div> <div class="product-info"> <h3 class="product-name">Laptop</h3> <span class="product-price">$350.00</span> <p class="product-description"> Now with this lovely piece of hardware you may dev anywhere! </p> </div> <div class="button-wrapper"> <button class="add-btn" id="366536"> Add to Cart </button> </div> </div> Now that we have our product card template we can copy and paste as many as we want inside the wrapper. I will just add a cup of coffee and headphones to complete my dev kit catalog. <div class="products-wrapper"> <div class="product-card"> <div class="product-img"> <img src="images/laptop.png" alt="laptop" title="laptop"> </div> <div class="product-info"> <h3 class="product-name">Laptop</h3> <span class="product-price">$350.00</span> <p class="product-description"> Now with this lovely piece of hardware you may dev anywhere! </p> </div> <div class="button-wrapper"> <button class="add-btn" id="366536"> Add to Cart </button> </div> </div> <div class="product-card"> <div class="product-img"> <img src="images/coffee.png" alt="coffee" title="coffee"> </div> <div class="product-info"> <h3 class="product-name">Coffee</h3> <span class="product-price">$3.99</span> <p class="product-description"> Sure you could try to dev without coffee, but who wants that? </p> </div> <div class="button-wrapper"> <button class="add-btn" id="95400"> Add to Cart </button> </div> </div> <div class="product-card"> <div class="product-img"> <img src="images/headphones.png" alt="headphones" title="headphones"> </div> <div class="product-info"> <h3 class="product-name">Headphones</h3> <span class="product-price">$49.99</span> <p class="product-description"> In a noisy world it can be hard to get into that flow state without these. </p> </div> <div class="button-wrapper"> <button class="add-btn" id="212653"> Add to Cart </button> </div> </div> </div> Now we must style it so everything is formatted well. We add the same side padding to our sections so it stays inline with the nav bar elements. Then use flexbox in the products wrapper for easy spacing. Since I have 3 products I will give each product card a width of 33%. You may style it however you’d like. I’ll keep the background color the same and give them a shadow. .product-section { padding: 20px 10%; } .products-heading { margin-top: 20px; } .products-wrapper { color: var(--main-dark-color); padding: 20px 0; display: flex; justify-content: space-between; gap: 30px; } .product-card { width: 33%; background-color: var(--main-light-color); border-radius: 10px; box-shadow: 0 0 10px 5px rgb(0,0,0,0.4); padding: 20px; font-size: 18px; } Next we will style the inside of the card. This code will center the images and give them equal dimensions. We’ll make the name bold and give the price a different color that goes good with the color scheme. For the button I will give it the dark background color and float it to the right. Then give it a hover effect. .product-img { text-align: center; margin: 0 auto; } .product-img img { object-fit: contain; width: 200px; height: 200px; border-radius: 10px 10px 0 0; } .product-name { margin: 10px 0 5px; } .product-price { color: var(--main-comp-color); } .product-description { font-size: 16px; } .add-btn { box-shadow: 0 0 3px 1px rgb(0,0,0,0.4); background-color: var(--main-dark-color); color: var(--main-light-color); border: none; padding: 10px; text-align: center; border-radius: 5px; float: right; } .add-btn:hover { color: var(--main-comp-color); cursor: pointer; box-shadow: none; } Shopping Cart Functionality with Javascript Finally we must make our cart functional so that when a customer clicks to add the product we store that product data and show the cart quantity in the top right. We’ll first create a javascript file and call it “main.js”. Link to it at the bottom of our HTML page. <script src="main.js"></script> </body> </html> Inside our javascript file we are going to need the cart quantity element and the add-to-cart buttons. So we select them like so. let navCartCount = document.getElementsByClassName('nav-cart-count')[0]; let addBtns = document.getElementsByClassName('add-btn'); addBtns = [].slice.call(addBtns); addBtns.forEach(ele => { ele.addEventListener('click', addToCart); }); When grabbing one element with a class name be sure to put the “[0]” at the end as this specifies the first and only index in the list. To add a click event to each button we can first turn the HTML object of buttons into an array by using [].slice.call. Once we have our array of “add-to-cart” buttons we’ll loop through each one to add a click event that will call a function named “addToCart”. We also need the product data. Sure we could get it from the product card elements themselves but that would mean we would have to dig deep inside the DOM which would result in some complex code. Real ecommerce sites would probably use an API to grab the product data but that is beyond the scope of this post. Instead we will just create an array of product objects inside the javascript file. productData = [ { id: 366536, img_path: 'laptop.png', name: 'Laptop', price: 350.00 }, { id: 95400, img_path: 'coffee.png', name: 'Coffee', price: 3.99 }, { id: 212653, img_path: 'headphones.png', name: 'Headphones', price: 49.99 } ]; One more thing before we build the functionality. We should always make sure that our javascript file knows what the state of the cart is whenever changes are made. We can make a simple state object that will keep track of what items are in the cart and how many. state = { cartQty: 0, cartItems: [] }; Whenever a customer clicks on one of the add-to-cart buttons we want to update the state object as well as the cart quantity element on our nav bar so the customer can see. Let’s implement this with the addToCart event listener we gave to each button. First we want to make sure we have access to the correct product. If you look back inside the HTML file you will notice the id in each button element matches the id inside productData. The ‘this’ keyword refers to the button element. We can log the id like this so every time you click a button it outputs the id of that product in the console. function addToCart(e) { let id = this.id; console.log(id); } Now with the id we must loop through the productData array to find the matching id. Then push that product in the cart item list inside state. Finally add 1 to the cartQty inside state. We also need to show the navCartCount element. We can set the style of display from ‘none’ to ‘block’. But since we want the number centered we will set it to ‘flex’. function addToCart(e) { let id = this.id; productData.forEach(product => { if(product['id'] == id) { state.cartItems.push(product); state.cartQty++; } }); navCartCount.style.display = 'flex'; navCartCount.innerHTML = state.cartQty; } Now when we add to cart the cart inside our state will keep pushing items even if they are the same. It is rather inefficient to have duplicate items. What we must do is check if the item is already stored in the state object. If it’s not we’ll give the product a quantity property ([‘qty’]) of 1 before pushing it to the list. If it is in the shopping cart we’ll simply iterate the quantity of that item. function addToCart(e) { let id = this.id; if(productInCart(id)) { return; } addProductData(id); } function productInCart(id) { let inCart = false; state.cartItems.forEach(item => { if(item['id'] == id) { item['qty']++; inCart = true; updateCartQty(); } }); return inCart; } function addProductData(id) { productData.forEach(product => { if(product['id'] == id) { product['qty'] = 1; state.cartItems.push(product); } }); updateCartQty(); } function updateCartQty() { navCartCount.innerHTML = ++state.cartQty; navCartCount.style.display = 'flex'; console.log(state); } Few things to point out here. As our task becomes more complex we must break it into separate functions. First we check if the product is in the cart already. If so it will iterate the item quantity, the cart quantity, and will end the addToCart function with the ‘return’ statement. If the item isn’t in the cart we’ll grab it from the productData, give it a ‘qty’ property of 1, and push it to the state cart. Since both cases lead to updating the cart quantity we put that in its own function to avoid repeating ourselves. Finally we console.log the state object to check and make sure the cart is being updated correctly. {cartQty: 7, cartItems: Array(3)} cartItems: Array(3) 0: {id: 212653, img_path: 'headphones.png', name: 'Headphones', price: 49.99, qty: 3} 1: {id: 95400, img_path: 'coffee.png', name: 'Coffee', price: 3.99, qty: 1} 2: {id: 366536, img_path: 'laptop.png', name: 'Laptop', price: 350, qty: 3} And that is how we create a basic shopping cart on the frontend using plain javascript. Of course carts can get very complicated. Like the customer should be able to add and subtract or remove the item from the cart and be able to see their cart. It should be saved in a session or temporarily in a database but that may be for a future post. CSS Javascript