Home/Components/Cards/Dynamic Product Cart Tailwind CSS and JavaScript
Code · Live Preview
Componenthtml
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Product Cart — Codekk</title>

  <!-- Fonts: matching system exactly -->
  <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+Serif+Display&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet" />

  <!-- Tailwind -->
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      theme: {
        extend: {
          fontFamily: {
            serif: ['DM Serif Display', 'serif'],
            sans:  ['DM Sans', 'sans-serif'],
          },
          colors: {
            ink:           '#111110',
            'ink-light':   '#1e1d1b',
            'off-white':   '#f5f4f1',
            'warm-muted':  '#888580',
            'warm-border': '#2a2927',
            'warm-mid':    '#e8e7e4',
            'warm-card':   '#ffffff',
            'warm-bg':     '#f5f4f1',
          },
        }
      }
    }
  </script>

  <link rel="stylesheet" href="style.css">
</head>
<body>

<!-- NAVBAR (matching system) -->
<nav style="background: rgba(245,244,241,0.92); border-bottom: 1px solid #e8e7e4; backdrop-filter: blur(12px); position: sticky; top: 0; z-index: 100;">
  <div class="max-w-[1280px] mx-auto px-6 lg:px-10">
    <div class="flex items-center justify-between h-[64px]">

      <!-- Logo -->
      <a href="#" class="flex items-center gap-2 no-underline">
        <div class="w-7 h-7 flex items-center justify-center rounded-[3px]" style="background:#111110;">
          <span class="font-serif text-[14px] text-off-white leading-none" style="color:#f5f4f1;">F</span>
        </div>
        <span class="font-serif text-[19px] text-ink tracking-tight leading-none">
          Formfield<span style="color:#888580;">.</span>
        </span>
      </a>

      <!-- Page title -->
      <span class="section-label hidden sm:block">Shop</span>

      <!-- Cart button -->
      <button id="open-cart" class="relative flex items-center gap-2 px-4 py-2 rounded-[4px] border border-warm-mid bg-white hover:border-warm-border transition-colors cursor-pointer"
              style="font-family:'DM Sans',sans-serif;">
        <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
          <path d="M1 1h2l2.4 7.2a1 1 0 0 0 .95.8h6.3a1 1 0 0 0 .95-.68L15 4H4" stroke="#111110" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
          <circle cx="6.5" cy="13.5" r="1" fill="#111110"/>
          <circle cx="12.5" cy="13.5" r="1" fill="#111110"/>
        </svg>
        <span class="text-[13px] font-medium text-ink hidden sm:inline">Cart</span>
        <div id="cart-count" class="hidden">0</div>
      </button>

    </div>
  </div>
</nav>


<!-- MAIN CONTENT -->
<main class="max-w-[1280px] mx-auto px-6 lg:px-10 py-12">

  <!-- Header row -->
  <div class="flex flex-col sm:flex-row sm:items-end justify-between gap-4 mb-8">
    <div>
      <p class="section-label mb-2">Our Products</p>
      <h1 class="font-serif text-[2rem] text-ink leading-tight" style="letter-spacing:-0.02em;">
        Curated Collection
      </h1>
    </div>
    <p class="text-[14px] text-warm-muted" id="product-count">Showing 8 products</p>
  </div>

  <!-- Filter bar -->
  <div class="flex gap-2 flex-wrap mb-8" id="filter-bar">
    <button class="filter-btn active" data-filter="all">All</button>
    <button class="filter-btn" data-filter="design">Design</button>
    <button class="filter-btn" data-filter="development">Development</button>
    <button class="filter-btn" data-filter="strategy">Strategy</button>
  </div>

  <!-- Divider -->
  <div class="h-px bg-warm-mid mb-8"></div>

  <!-- Products grid -->
  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5" id="products-grid">
    <!-- Rendered by JS -->
  </div>

</main>


<!-- CART OVERLAY -->
<div id="cart-overlay"></div>


<!-- CART SIDEBAR -->
<div id="cart-sidebar">

  <!-- Header -->
  <div class="flex items-center justify-between px-6 py-5" style="border-bottom:1px solid #e8e7e4;">
    <div>
      <p class="section-label mb-1">Your Cart</p>
      <h2 class="font-serif text-[1.3rem] text-ink leading-none" style="letter-spacing:-0.01em;">
        Order Summary
      </h2>
    </div>
    <button id="close-cart" class="w-8 h-8 flex items-center justify-center rounded-[4px] border border-warm-mid hover:border-warm-border hover:bg-warm-bg transition-colors cursor-pointer bg-white">
      <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
        <path d="M1 1l10 10M11 1L1 11" stroke="#888580" stroke-width="1.5" stroke-linecap="round"/>
      </svg>
    </button>
  </div>

  <!-- Cart items -->
  <div id="cart-items-scroll" class="flex-1 overflow-y-auto px-6">
    <!-- Empty state -->
    <div id="empty-cart">
      <div class="w-12 h-12 rounded-[4px] border border-warm-mid flex items-center justify-center mb-2">
        <svg width="22" height="22" viewBox="0 0 22 22" fill="none">
          <path d="M2 2h2.5l3 9.5a1.2 1.2 0 0 0 1.15.9h7.5a1.2 1.2 0 0 0 1.15-.86L19.5 6H5.5" stroke="#888580" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
          <circle cx="9" cy="19" r="1.2" fill="#888580"/>
          <circle cx="16" cy="19" r="1.2" fill="#888580"/>
        </svg>
      </div>
      <p class="text-[14px] font-medium text-ink">Your cart is empty</p>
      <p class="text-[13px] text-warm-muted">Add products to get started</p>
      <button id="empty-browse" class="btn-outline mt-2" style="font-size:13px; padding:8px 16px;">
        Browse products
      </button>
    </div>

    <!-- Items list (shown when not empty) -->
    <div id="cart-items-list" class="hidden py-2">
      <!-- Items rendered by JS -->
    </div>
  </div>

  <!-- Footer: totals + checkout -->
  <div id="cart-footer" class="hidden px-6 py-5" style="border-top:1px solid #e8e7e4;">

    <!-- Subtotals -->
    <div class="flex flex-col gap-2 mb-4">
      <div class="flex justify-between text-[13px]">
        <span class="text-warm-muted">Subtotal</span>
        <span class="text-ink font-medium" id="subtotal-val">$0.00</span>
      </div>
      <div class="flex justify-between text-[13px]">
        <span class="text-warm-muted">Shipping</span>
        <span class="text-ink">Free</span>
      </div>
      <div class="h-px bg-warm-mid my-1"></div>
      <div class="flex justify-between text-[14px]">
        <span class="font-medium text-ink">Total</span>
        <span class="font-serif text-[1.15rem] text-ink" id="total-val">$0.00</span>
      </div>
    </div>

    <!-- Promo code -->
    <div class="flex gap-2 mb-4">
      <input
        id="promo-input"
        type="text"
        placeholder="Promo code"
        class="flex-1 h-[38px] bg-warm-bg border border-warm-mid rounded-[4px] text-[13px] text-ink px-3 placeholder:text-warm-muted font-sans outline-none"
        style="transition: border-color 0.15s ease; font-family:'DM Sans',sans-serif;"
        onfocus="this.style.borderColor='#2a2927'" onblur="this.style.borderColor=''"
      />
      <button onclick="applyPromo()" class="btn-outline" style="padding:0 14px; height:38px; font-size:13px;">Apply</button>
    </div>
    <div id="promo-msg" class="text-[12px] text-warm-muted mb-3 hidden"></div>

    <!-- Checkout -->
    <button class="btn-primary w-full justify-center" style="padding:12px 20px; font-size:14px;" onclick="checkout()">
      Checkout <span class="arrow">→</span>
    </button>
    <p class="text-[11px] text-warm-muted text-center mt-3" style="letter-spacing:0.02em;">
      We respond within 24 hours
    </p>

  </div>
</div>


<!-- Toast -->
<div id="toast"></div>


<!-- Add your JS in app.js -->
<script src="app.js"></script>

</body>
</html>
Detecting libraries...

Component details

Overview, install command, dependencies, and project links.

A fully dynamic product cart page built with pure HTML, Tailwind CSS, and vanilla JavaScript — no frameworks, no dependencies. Features an 8-product grid with live category filtering, a slide-in cart sidebar with overlay, real-time quantity controls, line totals, promo code input, and an animated cart badge. Products are organized into Design, Development, and Strategy categories — switching filters updates the grid and product count instantly. The cart sidebar handles empty state, item addition and removal, quantity increment and decrement, and a checkout flow. Typography uses DM Serif Display for prices and headings, DM Sans for all body and UI text, on a warm #f5f4f1 background with #111110 ink, #888580 muted gray, and #e8e7e4 borders — no gradients, no colored accents, nothing decorative that doesn't earn its place.

Added Apr 17, 2026

Discussion

Feedback, implementation tips, and usage notes.

0 threads

Comments

Sign in to join the conversation

Similar Components

More from the same category