How to Make Shopping Cart using HTML, JS, CSS

Piyush608 top freelancer india 4

Creating a shopping cart using HTML, CSS, and JavaScript involves setting up a user interface for displaying products, adding products to the cart, viewing the cart, and removing products from the cart. Here’s a step-by-step guide to building a basic shopping cart:

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Online Store</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"
    />

    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <nav>
      <div class="container">
        <strong class="logo">Online Store</strong>

        <button class="cart-btn">
          <i class="bi bi-cart"></i>

          <small class="cart-qty">0</small>
        </button>
      </div>
    </nav>

    <main>
      <div class="container">
        <div class="products"></div>
      </div>
    </main>

    <div class="cart-overlay"></div>

    <div class="cart">
      <div class="cart-header">
        <i class="bi bi-arrow-right cart-close"></i>
        <h2>Your Cart</h2>
      </div>
      <div class="cart-body"></div>
      <div class="cart-footer">
        <div>
          <strong>Total</strong>
          <span class="cart-total">0</span>
        </div>
        <button class="cart-clear">Clear Cart</button>
        <button class="checkout">Checkout</button>
      </div>
    </div>

    <script src="script.js"></script>
  </body>
</html>

 

CSS (styles.css)

@import url("https://fonts.googleapis.com/css2?family=Jost:wght@400;500;600&display=swap");

:root {
  --color1: #ab4e68;
  --color2: #b07156;
  --color3: #533745;
  --color4: #9d9171;
  --color5: #c4a287;
  --color6: #4a646c;
  --color7: #333;
  --color8: #fff;
  --transition: all 0.3s ease-in-out;
}

* {
  font-family: "Jost", sans-serif;
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

body {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 30px;
  min-height: 100vh;
}

/* prevent body scroll when cart is open */
body:has(.show) {
  overflow: hidden;
}

button {
  cursor: pointer;
  border: none;
  border-radius: 3px;
  padding: 3px 10px;
  transition: var(--transition);
}

img {
  width: 100%;
  height: auto;
  display: block;
}

nav {
  background: var(--color1);
  color: var(--color8);
  padding-block: 20px;
}

nav > .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.logo {
  text-transform: uppercase;
}

.cart-btn {
  padding: 3px 8px;
  background: transparent;
  color: inherit;
  position: relative;
}

.cart-btn .bi {
  font-size: 1.5rem;
}

.cart-btn:hover {
  background: var(--color5);
}

.cart-qty {
  position: absolute;
  top: 0;
  right: 0;
  transform: translate(50%, -50%);
  background: var(--color7);
  padding: 0 5px;
  border-radius: 3px;
  display: none;
}

.cart-qty.visible {
  display: block;
}

.container {
  max-width: 1200px;
  width: 90%;
  margin: auto;
}

.products {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

.product {
  text-align: center;
  position: relative;
}

.product img {
  height: 250px;
  object-fit: contain;
}

.product:hover img {
  opacity: 0.75;
}

.product h3 {
  margin-top: 10px;
  color: var(--color4);
  font-size: 1rem;
}

.product h5 {
  margin-top: 5px;
  color: var(--color6);
}

.product button {
  position: absolute;
  top: 10px;
  right: 10px;
  background: var(--color1);
  color: var(--color8);
  padding: 5px 10px;
  font-size: 1rem;
  display: flex;
  align-items: center;
  gap: 5px;
  opacity: 0;
}

.product:hover button {
  opacity: 1;
}

.product button::before {
  font-family: "bootstrap-icons";
  font-size: 1.5rem;
  content: "\F23F";
}

.product button:disabled::before {
  content: "\F23A";
}

.product button:hover {
  background: var(--color2);
}

.product button:disabled {
  background: var(--color3);
  filter: brightness(1.75);
}

/* cart */

.cart-overlay {
  position: fixed;
  inset: 0;
  opacity: 0.5;
  visibility: hidden;
  cursor: pointer;
  background: var(--color7);
  transition: var(--transition);
}

.cart-overlay.show {
  visibility: visible;
}

.cart {
  position: fixed;
  inset-block: 0;
  right: 0;
  width: 100%;
  max-width: 420px;
  padding: 20px;
  display: grid;
  grid-template-rows: auto 1fr auto;
  transform: translateX(100%);
  transition: var(--transition);
  background: var(--color8);
}

.cart.show {
  transform: none;
}

.cart-header {
  position: relative;
  text-align: center;
  padding-block: 10px;
  border-bottom: 1px solid #ddd;
}

.cart-close {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.5rem;
  cursor: pointer;
}

.cart-body {
  display: grid;
  align-content: start;
  gap: 20px;
  padding-block: 20px;
  overflow: auto;
}

/* hide footer if the cart is empty */
.cart-body:has(.cart-empty) + .cart-footer {
  display: none;
}

.cart-empty {
  text-align: center;
  padding-block: 20px;
  font-size: 1.25rem;
  color: var(--color6);
}

.cart-item {
  display: flex;
  gap: 10px;
}

.cart-item img {
  width: 100px;
  height: 100px;
  object-fit: contain;
}

.cart-item-detail {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.cart-item-detail h3 {
  font-size: 1rem;
  color: var(--color4);
}

.cart-item-detail h5 {
  color: var(--color6);
}

.cart-item-amount {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1.25rem;
}

.cart-item-amount .bi {
  cursor: pointer;
  opacity: 0.25;
}

.cart-item-amount .bi:hover {
  opacity: 1;
}

.cart-item-amount .qty {
  width: 2rem;
  text-align: center;
}

.cart-item-price {
  margin-left: auto;
}

.cart-footer {
  border-top: 1px solid #ddd;
  padding-block: 10px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.cart-footer div {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 1.25rem;
}

.cart-footer strong {
  font-weight: 500;
  color: var(--color4);
}

.cart-footer button {
  padding-block: 10px;
  text-transform: uppercase;
}

.cart-clear {
  background: var(--color7);
  color: var(--color8);
}

.cart-clear:hover {
  filter: brightness(1.75);
}

.checkout {
  background: var(--color1);
  color: var(--color8);
}

.checkout:hover {
  background: var(--color2);
}

 

JavaScript (script.js)

let products = [];
let cart = [];

//* selectors

const selectors = {
  products: document.querySelector(".products"),
  cartBtn: document.querySelector(".cart-btn"),
  cartQty: document.querySelector(".cart-qty"),
  cartClose: document.querySelector(".cart-close"),
  cart: document.querySelector(".cart"),
  cartOverlay: document.querySelector(".cart-overlay"),
  cartClear: document.querySelector(".cart-clear"),
  cartBody: document.querySelector(".cart-body"),
  cartTotal: document.querySelector(".cart-total"),
};

//* event listeners

const setupListeners = () => {
  document.addEventListener("DOMContentLoaded", initStore);

  // product event
  selectors.products.addEventListener("click", addToCart);

  // cart events
  selectors.cartBtn.addEventListener("click", showCart);
  selectors.cartOverlay.addEventListener("click", hideCart);
  selectors.cartClose.addEventListener("click", hideCart);
  selectors.cartBody.addEventListener("click", updateCart);
  selectors.cartClear.addEventListener("click", clearCart);
};

//* event handlers

const initStore = () => {
  loadCart();
  loadProducts("https://fakestoreapi.com/products")
    .then(renderProducts)
    .finally(renderCart);
};

const showCart = () => {
  selectors.cart.classList.add("show");
  selectors.cartOverlay.classList.add("show");
};

const hideCart = () => {
  selectors.cart.classList.remove("show");
  selectors.cartOverlay.classList.remove("show");
};

const clearCart = () => {
  cart = [];
  saveCart();
  renderCart();
  renderProducts();
  setTimeout(hideCart, 500);
};

const addToCart = (e) => {
  if (e.target.hasAttribute("data-id")) {
    const id = parseInt(e.target.dataset.id);
    const inCart = cart.find((x) => x.id === id);

    if (inCart) {
      alert("Item is already in cart.");
      return;
    }

    cart.push({ id, qty: 1 });
    saveCart();
    renderProducts();
    renderCart();
    showCart();
  }
};

const removeFromCart = (id) => {
  cart = cart.filter((x) => x.id !== id);

  // if the last item is remove, close the cart
  cart.length === 0 && setTimeout(hideCart, 500);

  renderProducts();
};

const increaseQty = (id) => {
  const item = cart.find((x) => x.id === id);
  if (!item) return;

  item.qty++;
};

const decreaseQty = (id) => {
  const item = cart.find((x) => x.id === id);
  if (!item) return;

  item.qty--;

  if (item.qty === 0) removeFromCart(id);
};

const updateCart = (e) => {
  if (e.target.hasAttribute("data-btn")) {
    const cartItem = e.target.closest(".cart-item");
    const id = parseInt(cartItem.dataset.id);
    const btn = e.target.dataset.btn;

    btn === "incr" && increaseQty(id);
    btn === "decr" && decreaseQty(id);

    saveCart();
    renderCart();
  }
};

const saveCart = () => {
  localStorage.setItem("online-store", JSON.stringify(cart));
};

const loadCart = () => {
  cart = JSON.parse(localStorage.getItem("online-store")) || [];
};

//* render functions

const renderCart = () => {
  // show cart qty in navbar
  const cartQty = cart.reduce((sum, item) => {
    return sum + item.qty;
  }, 0);

  selectors.cartQty.textContent = cartQty;
  selectors.cartQty.classList.toggle("visible", cartQty);

  // show cart total
  selectors.cartTotal.textContent = calculateTotal().format();

  // show empty cart
  if (cart.length === 0) {
    selectors.cartBody.innerHTML =
      '<div class="cart-empty">Your cart is empty.</div>';
    return;
  }

  // show cart items
  selectors.cartBody.innerHTML = cart
    .map(({ id, qty }) => {
      // get product info of each cart item
      const product = products.find((x) => x.id === id);

      const { title, image, price } = product;

      const amount = price * qty;

      return `
        <div class="cart-item" data-id="${id}">
          <img src="${image}" alt="${title}" />
          <div class="cart-item-detail">
            <h3>${title}</h3>
            <h5>${price.format()}</h5>
            <div class="cart-item-amount">
              <i class="bi bi-dash-lg" data-btn="decr"></i>
              <span class="qty">${qty}</span>
              <i class="bi bi-plus-lg" data-btn="incr"></i>

              <span class="cart-item-price">
                ${amount.format()}
              </span>
            </div>
          </div>
        </div>`;
    })
    .join("");
};

const renderProducts = () => {
  selectors.products.innerHTML = products
    .map((product) => {
      const { id, title, image, price } = product;

      // check if product is already in cart
      const inCart = cart.find((x) => x.id === id);

      // make the add to cart button disabled if already in cart
      const disabled = inCart ? "disabled" : "";

      // change the text if already in cart
      const text = inCart ? "Added in Cart" : "Add to Cart";

      return `
    <div class="product">
      <img src="${image}" alt="${title}" />
      <h3>${title}</h3>
      <h5>${price.format()}</h5>
      <button ${disabled} data-id=${id}>${text}</button>
    </div>
    `;
    })
    .join("");
};

//* api functions

const loadProducts = async (apiURL) => {
  try {
    const response = await fetch(apiURL);
    if (!response.ok) {
      throw new Error(`http error! status=${response.status}`);
    }
    products = await response.json();
    console.log(products);
  } catch (error) {
    console.error("fetch error:", error);
  }
};

//* helper functions

const calculateTotal = () => {
  return cart
    .map(({ id, qty }) => {
      const { price } = products.find((x) => x.id === id);

      return qty * price;
    })
    .reduce((sum, number) => {
      return sum + number;
    }, 0);
};

Number.prototype.format = function () {
  return this.toLocaleString("en-US", {
    style: "currency",
    currency: "USD",
  });
};

//* initialize

setupListeners();

 

Explanation

  1. HTML Structure:
    • The HTML includes containers for products and the shopping cart, along with a heading and a total price display.
  2. CSS Styling:
    • The CSS styles the container, products, and cart items for a clean, modern look.
    • Products and cart items are styled with a border and some padding.
    • Buttons are styled for a consistent look with hover effects.
  3. JavaScript Functionality:
    • The JavaScript initializes an array of products and an empty cart array.
    • Functions to display products, add to cart, remove from cart, and update the total price are defined.
    • Event listeners are set up for adding and removing items from the cart.
    • The displayProducts function creates HTML elements for each product and adds them to the products container.
    • The displayCart function creates HTML elements for each cart item and adds them to the cart container, and also updates the total price.
    • The addToCart function adds a product to the cart array and updates the display.
    • The removeFromCart function removes a product from the cart array and updates the display.
    • The updateTotal function calculates the total price of items in the cart and updates the total display.

This setup provides a simple and functional shopping cart. You can expand it by adding more features like quantity selection, saving the cart to local storage, or integrating with a backend server for persistent data storage.

CEO Piyush Gupta


Reviews

There are no reviews yet. Be the first one to write one.


0.0
Rated 0 out of 5
0 out of 5 stars (based on 0 reviews)
Excellent0%
Very good0%
Average0%
Poor0%
Terrible0%