Simple Shopping Cart - JavaScript Cart Demo | Free Project

 

Build a Shopping Cart with JavaScript

A complete beginner-friendly tutorial with full source code

 

Simple Shopping Cart - JavaScript Cart

 

Introduction

Learning how to build a shopping cart JavaScript app from scratch is an excellent way for beginners to understand DOM manipulation, event handling, and local state management in the browser. In this tutorial you'll get a full, working project—no external API required—that demonstrates how to add items to a cart, change quantities, remove items, and persist the cart in localStorage. This step-by-step guide is beginner-friendly and optimized for SEO, so you can quickly publish it on your coding blog.

 

Why Build This Project

A small shopping cart JavaScript project teaches several core web development skills:

 

HTML & Semantic Tags

How to work with HTML structure and semantic tags for SEO.

 

DOM Manipulation

How to manipulate the DOM using JavaScript to reflect user actions.

 

Data Persistence

Client-side data persistence with localStorage.

 

Code Structure

How to structure code for readability and maintainability.

 

UI/UX Principles

Basic UI/UX ideas (buttons, counters, confirmation flows).

This project is ideal for beginners who want a practical, publishable portfolio piece and for bloggers who want an SEO-friendly tutorial to attract organic search traffic for keywords like shopping cart JavaScript, add to cart example, and JavaScript cart tutorial.

 

Features of This Project

Add products to the cart from a product list.
Increment and decrement product quantities.
Remove products from the cart.
Show cart total price and item count.
Save cart data in localStorage so the cart persists across page refreshes.
Clean, responsive layout with basic CSS (no frameworks).
Easy-to-follow, commented code for learning and reuse.

Keywords included naturally: shopping cart javascript, add to cart, cart example, localStorage cart.

 

Step-by-Step Explanation of Code

Below is a high-level plan before we show code:

 

HTML Structure

  • Header with site title (good for SEO).
  • Product list: each product has name, price, and Add to Cart button.
  • Cart area: shows items, quantities, subtotal, and total.
  • Footer with short description and call-to-action.

 

CSS

  • Simple responsive grid for products.
  • Fixed cart panel at the top-right on wide screens (mobile-friendly fallback).
  • Accessible button styles and hover states.

 

JavaScript

  • Keep product list as a static array in the script (no external API).
  • Render product cards to the DOM.
  • Manage cart state as an object: { id: {product, qty} }
  • Functions for addToCart, removeFromCart, updateQuantity, getCartTotal, renderCart.
  • Persist and load cart from localStorage.

 

Full Source Code (HTML, CSS, JS)

Save the following as a single file named index.html. It contains embedded CSS and JS so it's easy to publish and test.

index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Simple Shopping Cart — JavaScript Cart Demo</title>
  <meta name="description" content="Simple shopping cart JavaScript example: add, update, and remove items dynamically. Perfect beginner project with full HTML, CSS, and JS." />
  <link rel="canonical" href="https://yourdomain.com/simple-shopping-cart-javascript" />
  <style>
    /* Basic Reset */
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; line-height: 1.5; color: #111; background: #f7f8fb; padding: 20px; overflow-x: hidden; }

    /* Header */
    header { display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; }
    header h1 { font-size:1.25rem; }
    .subtitle { font-size:0.9rem; color:#666; }

    /* Layout */
    .container { display:grid; grid-template-columns: 1fr 320px; gap: 20px; align-items:start; position: relative; }
    @media (max-width: 900px) {
      .container { grid-template-columns: 1fr; }
    }

    /* Products Grid */
    .products { display:grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
    .card { background:#fff; border-radius:10px; padding:14px; box-shadow:0 2px 6px rgba(20,20,40,0.05); border:1px solid #eef2f6; display:flex; flex-direction:column; justify-content:space-between; min-height:150px; }
    .product-title { font-weight:600; margin-bottom:8px; }
    .product-price { color:#0a6bff; font-weight:700; margin-bottom:10px; }

    /* Buttons */
    .btn { display:inline-flex; align-items:center; justify-content:center; padding:8px 12px; border-radius:20px; border:0; cursor:pointer; background:#0a6bff; color:#fff; font-weight:600; }
    .btn.secondary { background:#fff; color:#0a6bff; border:1px solid #dbe9ff; }
    .btn:active { transform:translateY(1px); }

    /* Cart */
    .cart {
      background:#fff;
      border-radius:10px;
      padding:16px;
      box-shadow:0 2px 10px rgba(20,20,40,0.05);
      border:1px solid #eef2f6;
      position:fixed;
      top:100px;
      right:40px;
      width:300px;
      max-height:calc(100vh - 140px);
      overflow-y:auto;
      overflow-x:hidden;
    }

    .cart h2 { font-size:1rem; margin-bottom:12px; }
    .cart-empty { color:#666; font-size:0.95rem; text-align:center; }

    .cart-list { display:flex; flex-direction:column; gap:10px; margin-bottom:12px; padding-right:6px; }

    .cart-item {
      background:#f9fbff;
      border:1px solid #e3ecff;
      border-radius:10px;
      padding:10px 12px;
      display:flex;
      flex-direction:column;
      justify-content:space-between;
      gap:6px;
    }

    .cart-item .top-line {
      display:flex;
      justify-content:space-between;
      align-items:center;
    }

    .cart-item .top-line .left {
      display:flex;
      flex-direction:column;
      gap:2px;
    }

    .cart-item .bottom-line {
      display:flex;
      justify-content:space-between;
      align-items:center;
      flex-wrap:wrap;
      gap:8px;
    }

    .qty-control { display:flex; align-items:center; gap:6px; }
    .qty-btn { width:26px; height:26px; border-radius:6px; background:#fff; border:1px solid #dbe9ff; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; }

    .total { margin-top:12px; font-weight:700; display:flex; justify-content:space-between; align-items:center; }
    .checkout { margin-top:10px; width:100%; }

    footer { margin-top:20px; color:#666; font-size:0.95rem; }

    /* Small helper */
    .muted { color:#777; font-size:0.95rem; }

    /* Scrollable product area */
    section {
      height:100vh;
      overflow-y:auto;
      padding-right:10px;
    }

    /* Responsive fix for mobile */
    @media (max-width:900px) {
      aside.cart {
        position:static;
        width:100%;
        max-height:none;
        right:0;
        top:auto;
      }
      section {
        height:auto;
        overflow:visible;
      }
    }
  </style>
</head>
<body>

  <header>
    <div>
      <h1>Simple Shopping Cart</h1>
      <div class="subtitle">A beginner-friendly <strong>shopping cart JavaScript</strong> demo</div>
    </div>
    <div class="muted">No API • Local storage • Vanilla JS</div>
  </header>

  <main class="container">
    <section>
      <h2 style="margin-bottom:10px">Products</h2>
      <div class="products" id="products"></div>
    </section>

    <aside class="cart" aria-label="Shopping cart">
      <h2>Cart <small id="cart-count" style="font-weight:400;color:#666"> (0 items)</small></h2>
      <div id="cart-list" class="cart-list">
        <div class="cart-empty">Your cart is empty. Add items to see them here.</div>
      </div>

      <div class="total">
        <div>Subtotal</div>
        <div id="cart-total">₹0.00</div>
      </div>
      <button class="btn checkout" id="clear-cart">Clear Cart</button>
    </aside>
  </main>

  <footer>
    <p>Project: <strong>Simple Shopping Cart</strong> — <em>Add and remove items dynamically in cart.</em></p>
  </footer>

  <script>
    /* =========
       Simple Shopping Cart (Vanilla JS)
       - No external API
       - Data persisted in localStorage under key 'simple_cart'
       ========= */

    const PRODUCTS = [
      { id: 'p1', name: 'Basic T-shirt', price: 399, desc: 'Comfortable cotton t-shirt' },
      { id: 'p2', name: 'Classic Mug', price: 249, desc: 'Ceramic coffee mug, 350ml' },
      { id: 'p3', name: 'Notebook', price: 129, desc: 'A5 ruled notebook, 100 pages' },
      { id: 'p4', name: 'Desk Lamp', price: 1599, desc: 'Adjustable LED desk lamp' },
      { id: 'p5', name: 'Phone Stand', price: 299, desc: 'Foldable phone stand' },
      { id: 'p6', name: 'Water Bottle', price: 449, desc: 'Stainless steel, 700ml' }
    ];

    const STORAGE_KEY = 'simple_cart';
    let cart = {};

 // ---------- Utility functions ----------
    function formatCurrency(amount) {
      return '₹' + amount.toFixed(2);
    }

    function saveCart() {
      try { localStorage.setItem(STORAGE_KEY, JSON.stringify(cart)); }
      catch (e) { console.error('Could not save cart', e); }
    }

    function loadCart() {
      try {
        const raw = localStorage.getItem(STORAGE_KEY);
        if (!raw) return {};
        return JSON.parse(raw);
      } catch (e) {
        console.error('Could not load cart', e);
        return {};
      }
    }

 // ---------- Rendering functions ----------
    const productsEl = document.getElementById('products');
    const cartListEl = document.getElementById('cart-list');
    const cartTotalEl = document.getElementById('cart-total');
    const cartCountEl = document.getElementById('cart-count');

    function renderProducts() {
      productsEl.innerHTML = '';
      PRODUCTS.forEach(p => {
        const card = document.createElement('div');
        card.className = 'card';
        card.innerHTML = `
          <div>
            <div class="product-title">${p.name}</div>
            <div class="muted">${p.desc}</div>
          </div>

          <div style="margin-top:12px; display:flex; justify-content:space-between; align-items:center;">
            <div>
              <div class="product-price">${formatCurrency(p.price)}</div>
            </div>
            <div>
              <button class="btn" data-id="${p.id}" aria-label="Add ${p.name} to cart">Add to Cart</button>
            </div>
          </div>
        `;
        productsEl.appendChild(card);
      });

// attach click listeners to Add buttons
      productsEl.querySelectorAll('button[data-id]').forEach(btn => {
        btn.addEventListener('click', () => {
          const id = btn.getAttribute('data-id');
          addToCart(id);
        });
      });
    }

    function renderCart() {
      cartListEl.innerHTML = '';

      const keys = Object.keys(cart);
      if (keys.length === 0) {
        cartListEl.innerHTML = '<div class="cart-empty">Your cart is empty. Add items to see them here.</div>';
        cartTotalEl.textContent = formatCurrency(0);
        cartCountEl.textContent = ' (0 items)';
        return;
      }

      let total = 0, count = 0;

      keys.forEach(id => {
        const entry = cart[id];
        const subtotal = entry.product.price * entry.qty;
        total += subtotal;
        count += entry.qty;

        const item = document.createElement('div');
        item.className = 'cart-item';
        item.innerHTML = `
          <div class="top-line">
            <div class="left">
              <div style="font-weight:600">${entry.product.name}</div>
              <div class="muted" style="font-size:0.9rem">${formatCurrency(entry.product.price)} each</div>
            </div>
            <div style="font-weight:600;color:#0a6bff;">${formatCurrency(subtotal)}</div>
          </div>

          <div class="bottom-line">
            <div class="qty-control" data-id="${id}">
              <button class="qty-btn" aria-label="Decrease quantity">-</button>
              <div style="min-width:26px; text-align:center;">${entry.qty}</div>
              <button class="qty-btn" aria-label="Increase quantity">+</button>
            </div>
            <button class="btn secondary" data-remove="${id}" aria-label="Remove ${entry.product.name}">Remove</button>
          </div>
        `;
        cartListEl.appendChild(item);
      });

      cartTotalEl.textContent = formatCurrency(total);
      cartCountEl.textContent = ` (${count} item${count > 1 ? 's' : ''})`;

      cartListEl.querySelectorAll('.qty-control').forEach(el => {
        const id = el.getAttribute('data-id');
        const buttons = el.querySelectorAll('.qty-btn');
        if (buttons[0]) buttons[0].addEventListener('click', () => updateQuantity(id, cart[id].qty - 1));
        if (buttons[1]) buttons[1].addEventListener('click', () => updateQuantity(id, cart[id].qty + 1));
      });

      cartListEl.querySelectorAll('button[data-remove]').forEach(btn => {
        btn.addEventListener('click', () => {
          const id = btn.getAttribute('data-remove');
          removeFromCart(id);
        });
      });
    }

// ---------- Cart operations ----------

    function addToCart(productId) {
      const product = PRODUCTS.find(p => p.id === productId);
      if (!product) return;
      if (!cart[productId]) cart[productId] = { product, qty: 1 };
      else cart[productId].qty += 1;
      saveCart(); renderCart();
    }

    function removeFromCart(productId) {
      if (!cart[productId]) return;
      delete cart[productId];
      saveCart(); renderCart();
    }

    function updateQuantity(productId, newQty) {
      if (!cart[productId]) return;
      if (newQty <= 0) return removeFromCart(productId);
      cart[productId].qty = newQty;
      saveCart(); renderCart();
    }

    document.getElementById('clear-cart').addEventListener('click', () => {
      if (confirm('Clear the entire cart?')) {
        cart = {}; saveCart(); renderCart();
      }
    });

    (function init() {
      cart = loadCart() || {};
      renderProducts();
      renderCart();
    })();
  </script>
</body>
</html>

 

How It Works (code explanation in simple words)

High-level flow (plain English):

  1. The page contains a static array of products (so there's no need for an external API). Each product has an id, name, price, and description.
  2. When the page loads, the script:
    • Loads any existing cart data from the browser's localStorage.
    • Renders product cards and the cart UI.
  3. When a user clicks Add to Cart, the addToCart(productId) function:
    • Finds the product in the products array.
    • Adds it to the cart object or increases its quantity.
    • Saves the updated cart object to localStorage and re-renders the cart.
  4. The cart shows each item with:
    • Quantity controls (+ and - buttons) that call updateQuantity.
    • A Remove button to delete an item immediately.
    • A subtotal for each item and a grand total at the bottom.
  5. Clearing the cart empties the stored cart and re-renders the UI.

 

Why use localStorage?

localStorage keeps the cart available even after the user reloads the page or closes and re-opens the browser. It's perfect for small demo projects where server-side sessions are unnecessary.

 

Key functions to inspect:

  • renderProducts() — builds the product list UI and attaches "Add to Cart" listeners.
  • renderCart() — builds the cart UI from the cart object and attaches quantity/remove listeners.
  • addToCart(), removeFromCart(), updateQuantity() — core cart mutators.
  • saveCart() and loadCart() — manage persistence.

 

Accessibility & SEO notes:

  • Buttons include aria-label attributes for screen readers.
  • Text content for product names and descriptions are visible and crawlable by search engines, which improves discoverability for keywords like shopping cart javascript.

 

Conclusion with CTA

You now have a complete, beginner-friendly shopping cart JavaScript project: a single-file example that you can copy, customize, and publish on your blog. This demo demonstrates DOM handling, state management, and local storage—core skills for building real web apps.

Call to action:

Try this project now: copy the HTML file above, save it as "index.html", and open it in your browser. Customize product names, currency, and styling to match your brand. If you publish this tutorial on your blog, add the demo link with readers. Want me to extend this project (coupon codes, checkout simulation, or product filtering)? Tell me which feature you want next and I'll provide the code and blog update.



View Demo
Previous Post Next Post