Snippets Cart

Bootstrap 5 Product List with Add to Cart Animation

A responsive product grid where each Add button turns into a quantity stepper and updates a live cart badge and total.

Bootstrap 5 No jQuery Aug 2020 2K views

<section class="wdw-stage">
  <div class="container" style="max-width:1100px">
    <div class="d-flex flex-wrap align-items-end justify-content-between gap-3 mb-4">
      <div>
        <span class="wdw-eyebrow">New arrivals</span>
        <h2 class="wdw-heading h2 mb-0">Shop the latest drops</h2>
      </div>
      <button type="button" class="btn btn-outline-primary rounded-pill position-relative me-2 pl-cart" aria-label="Cart, 0 items">
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="20" r="1.5"/><circle cx="18" cy="20" r="1.5"/><path d="M2 3h3l2.7 12.4a2 2 0 0 0 2 1.6h7.7a2 2 0 0 0 2-1.5L21 8H6"/></svg>
        <span class="pl-total">$0</span>
        <span class="pl-count badge rounded-pill bg-primary position-absolute top-0 start-100 translate-middle">0</span>
      </button>
    </div>
    <div class="row g-4">
      <div class="col-sm-6 col-lg-3">
        <article class="wdw-card pl-card h-100 p-3 d-flex flex-column" data-product="Crimson Runner" data-price="89">
          <div class="pl-media ratio ratio-1x1 rounded-4 overflow-hidden mb-3">
            <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=600&q=70" alt="Crimson Runner" loading="lazy">
          </div>
          <span class="wdw-eyebrow mb-1">Sneakers</span>
          <h3 class="h6 fw-bold mb-1 text-body-emphasis">Crimson Runner</h3>
          <p class="small wdw-muted mb-3">Lightweight trainer</p>
          <div class="d-flex align-items-center justify-content-between mt-auto gap-2">
            <span class="fs-5 fw-bold text-body-emphasis">$89</span>
            <div class="pl-action">
              <button type="button" class="btn btn-primary btn-sm rounded-pill px-3 pl-add"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Add</button>
              <div class="pl-stepper d-none align-items-center rounded-pill" role="group" aria-label="Quantity for Crimson Runner">
                <button type="button" class="pl-step" data-step="-1" aria-label="Remove one Crimson Runner">−</button>
                <span class="pl-qty fw-bold" aria-live="polite">1</span>
                <button type="button" class="pl-step" data-step="1" aria-label="Add one Crimson Runner">+</button>
              </div>
            </div>
          </div>
        </article>
      </div>
      <div class="col-sm-6 col-lg-3">
        <article class="wdw-card pl-card h-100 p-3 d-flex flex-column" data-product="Meridian Watch" data-price="129">
          <div class="pl-media ratio ratio-1x1 rounded-4 overflow-hidden mb-3">
            <img src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?auto=format&fit=crop&w=600&q=70" alt="Meridian Watch" loading="lazy">
          </div>
          <span class="wdw-eyebrow mb-1">Watches</span>
          <h3 class="h6 fw-bold mb-1 text-body-emphasis">Meridian Watch</h3>
          <p class="small wdw-muted mb-3">Steel case, 40mm</p>
          <div class="d-flex align-items-center justify-content-between mt-auto gap-2">
            <span class="fs-5 fw-bold text-body-emphasis">$129</span>
            <div class="pl-action">
              <button type="button" class="btn btn-primary btn-sm rounded-pill px-3 pl-add"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Add</button>
              <div class="pl-stepper d-none align-items-center rounded-pill" role="group" aria-label="Quantity for Meridian Watch">
                <button type="button" class="pl-step" data-step="-1" aria-label="Remove one Meridian Watch">−</button>
                <span class="pl-qty fw-bold" aria-live="polite">1</span>
                <button type="button" class="pl-step" data-step="1" aria-label="Add one Meridian Watch">+</button>
              </div>
            </div>
          </div>
        </article>
      </div>
      <div class="col-sm-6 col-lg-3">
        <article class="wdw-card pl-card h-100 p-3 d-flex flex-column" data-product="Halo Headphones" data-price="149">
          <div class="pl-media ratio ratio-1x1 rounded-4 overflow-hidden mb-3">
            <img src="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?auto=format&fit=crop&w=600&q=70" alt="Halo Headphones" loading="lazy">
          </div>
          <span class="wdw-eyebrow mb-1">Audio</span>
          <h3 class="h6 fw-bold mb-1 text-body-emphasis">Halo Headphones</h3>
          <p class="small wdw-muted mb-3">Wireless, 30h battery</p>
          <div class="d-flex align-items-center justify-content-between mt-auto gap-2">
            <span class="fs-5 fw-bold text-body-emphasis">$149</span>
            <div class="pl-action">
              <button type="button" class="btn btn-primary btn-sm rounded-pill px-3 pl-add"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Add</button>
              <div class="pl-stepper d-none align-items-center rounded-pill" role="group" aria-label="Quantity for Halo Headphones">
                <button type="button" class="pl-step" data-step="-1" aria-label="Remove one Halo Headphones">−</button>
                <span class="pl-qty fw-bold" aria-live="polite">1</span>
                <button type="button" class="pl-step" data-step="1" aria-label="Add one Halo Headphones">+</button>
              </div>
            </div>
          </div>
        </article>
      </div>
      <div class="col-sm-6 col-lg-3">
        <article class="wdw-card pl-card h-100 p-3 d-flex flex-column" data-product="Atlas Tee" data-price="34">
          <div class="pl-media ratio ratio-1x1 rounded-4 overflow-hidden mb-3">
            <img src="https://images.unsplash.com/photo-1583743814966-8936f5b7be1a?auto=format&fit=crop&w=600&q=70" alt="Atlas Tee" loading="lazy">
          </div>
          <span class="wdw-eyebrow mb-1">Apparel</span>
          <h3 class="h6 fw-bold mb-1 text-body-emphasis">Atlas Tee</h3>
          <p class="small wdw-muted mb-3">Organic cotton</p>
          <div class="d-flex align-items-center justify-content-between mt-auto gap-2">
            <span class="fs-5 fw-bold text-body-emphasis">$34</span>
            <div class="pl-action">
              <button type="button" class="btn btn-primary btn-sm rounded-pill px-3 pl-add"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Add</button>
              <div class="pl-stepper d-none align-items-center rounded-pill" role="group" aria-label="Quantity for Atlas Tee">
                <button type="button" class="pl-step" data-step="-1" aria-label="Remove one Atlas Tee">−</button>
                <span class="pl-qty fw-bold" aria-live="polite">1</span>
                <button type="button" class="pl-step" data-step="1" aria-label="Add one Atlas Tee">+</button>
              </div>
            </div>
          </div>
        </article>
      </div>
    </div>
  </div>
</section>

Built on Bootstrap 5.3.8 with plain JavaScript — no jQuery. Supports light and dark mode via data-bs-theme.

Free to use in personal and commercial projects under the MIT license.