Bootstrap 5 Tutorial
v5.3.0Bootstrap 5 Tutorial
E-commerce Page Project
Project Goal: Create a complete e-commerce product page with product listing, filtering, cart functionality, and checkout process.
Project Overview
This project demonstrates how to build a fully functional e-commerce product page using Bootstrap 5. The page includes product gallery, description, reviews, related products, shopping cart, and checkout process.
E-commerce Features
- Product listing with filtering
- Product detail page with gallery
- Shopping cart functionality
- Checkout process
- Customer reviews system
- Related products
- Wishlist functionality
- Order tracking
Shopping Features
- Add to cart functionality
- Quantity selectors
- Size and color selection
- Product variants
- Discount codes
- Shipping calculator
- Payment methods
- Order confirmation
Complete E-commerce Structure
HTML Layout
<!-- E-commerce Website -->
<!-- Top Bar -->
<div class="top-bar bg-dark text-white py-2 d-none d-md-block">
<div class="container">
<div class="row">
<div class="col-md-6">
<span class="small">
<i class="fas fa-truck me-1"></i> Free shipping on orders over $50
</span>
</div>
<div class="col-md-6 text-md-end">
<span class="small me-3">
<i class="fas fa-phone me-1"></i> +1 234 567 8900
</span>
<span class="small">
<i class="fas fa-envelope me-1"></i> support@store.com
</span>
</div>
</div>
</div>
</div>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm sticky-top">
<div class="container">
<!-- Logo -->
<a class="navbar-brand fw-bold fs-3" href="#">
<i class="fas fa-shopping-bag text-primary me-2"></i>ShopEasy
</a>
<!-- Search -->
<div class="mx-3 flex-grow-1 d-none d-lg-block">
<form class="d-flex">
<div class="input-group">
<input type="search" class="form-control" placeholder="Search products...">
<button class="btn btn-primary" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</form>
</div>
<!-- Cart & Account -->
<div class="d-flex align-items-center">
<!-- Wishlist -->
<a href="#" class="text-dark me-3 position-relative">
<i class="fas fa-heart fa-lg"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
3
</span>
</a>
<!-- Cart -->
<div class="dropdown me-3">
<a href="#" class="text-dark position-relative" data-bs-toggle="dropdown">
<i class="fas fa-shopping-cart fa-lg"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-primary">
2
</span>
</a>
<div class="dropdown-menu dropdown-menu-end p-3" style="width: 300px;">
<h6 class="dropdown-header">Shopping Cart</h6>
<div class="dropdown-item d-flex py-2">
<img src="https://via.placeholder.com/50" class="me-2" style="width: 50px; height: 50px; object-fit: cover;">
<div class="flex-grow-1">
<h6 class="mb-0">Wireless Headphones</h6>
<small class="text-muted">1 x $99.99</small>
</div>
<button class="btn btn-sm btn-outline-danger">
<i class="fas fa-times"></i>
</button>
</div>
<div class="dropdown-divider"></div>
<div class="d-flex justify-content-between mb-2">
<span>Subtotal:</span>
<span class="fw-bold">$149.98</span>
</div>
<div class="d-grid gap-2">
<a href="#" class="btn btn-primary">View Cart</a>
<a href="#" class="btn btn-outline-primary">Checkout</a>
</div>
</div>
</div>
<!-- Account -->
<div class="dropdown">
<a href="#" class="text-dark" data-bs-toggle="dropdown">
<i class="fas fa-user-circle fa-lg"></i>
</a>
<div class="dropdown-menu dropdown-menu-end">
<h6 class="dropdown-header">My Account</h6>
<a class="dropdown-item" href="#"><i class="fas fa-user me-2"></i> Profile</a>
<a class="dropdown-item" href="#"><i class="fas fa-box me-2"></i> Orders</a>
<a class="dropdown-item" href="#"><i class="fas fa-heart me-2"></i> Wishlist</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#"><i class="fas fa-sign-out-alt me-2"></i> Sign Out</a>
</div>
</div>
<!-- Mobile Menu Toggle -->
<button class="navbar-toggler ms-3" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<!-- Categories -->
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
Categories
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Electronics</a>
<a class="dropdown-item" href="#">Fashion</a>
<a class="dropdown-item" href="#">Home & Garden</a>
<a class="dropdown-item" href="#">Sports</a>
<a class="dropdown-item" href="#">Books</a>
</div>
</li>
<li class="nav-item"><a class="nav-link" href="#">Deals</a></li>
<li class="nav-item"><a class="nav-link" href="#">New Arrivals</a></li>
<li class="nav-item"><a class="nav-link" href="#">Best Sellers</a></li>
</ul>
<!-- Mobile Search -->
<form class="d-flex d-lg-none mt-3">
<div class="input-group">
<input type="search" class="form-control" placeholder="Search products...">
<button class="btn btn-primary" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</form>
</div>
</div>
</nav>
<!-- Product Listing Section -->
<section class="py-5">
<div class="container">
<!-- Breadcrumb -->
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Electronics</a></li>
<li class="breadcrumb-item"><a href="#">Headphones</a></li>
<li class="breadcrumb-item active" aria-current="page">Wireless Headphones</li>
</ol>
</nav>
<div class="row">
<!-- Sidebar Filters -->
<div class="col-lg-3 mb-4">
<div class="card">
<div class="card-header bg-light">
<h5 class="mb-0">Filters</h5>
</div>
<div class="card-body">
<!-- Price Range -->
<div class="mb-4">
<h6 class="mb-3">Price Range</h6>
<input type="range" class="form-range" min="0" max="1000" value="500">
<div class="d-flex justify-content-between">
<span>$0</span>
<span>$500</span>
<span>$1000</span>
</div>
</div>
<!-- Categories -->
<div class="mb-4">
<h6 class="mb-3">Categories</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="cat1">
<label class="form-check-label" for="cat1">Headphones</label>
<span class="badge bg-secondary float-end">42</span>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="cat2">
<label class="form-check-label" for="cat2">Speakers</label>
<span class="badge bg-secondary float-end">23</span>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="cat3">
<label class="form-check-label" for="cat3">Earbuds</label>
<span class="badge bg-secondary float-end">15</span>
</div>
</div>
<!-- Brand -->
<div class="mb-4">
<h6 class="mb-3">Brand</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="brand1">
<label class="form-check-label" for="brand1">Sony</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="brand2">
<label class="form-check-label" for="brand2">Bose</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="brand3">
<label class="form-check-label" for="brand3">Apple</label>
</div>
</div>
<!-- Rating -->
<div class="mb-4">
<h6 class="mb-3">Rating</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="rating" id="rating5">
<label class="form-check-label" for="rating5">
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
& Up
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="rating" id="rating4">
<label class="form-check-label" for="rating4">
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
& Up
</label>
</div>
</div>
<button class="btn btn-primary w-100">Apply Filters</button>
</div>
</div>
</div>
<!-- Product Grid -->
<div class="col-lg-9">
<!-- Sort and View Options -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<span class="text-muted">Showing 1-12 of 48 products</span>
</div>
<div class="d-flex gap-3">
<div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
Sort by: Featured
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Price: Low to High</a></li>
<li><a class="dropdown-item" href="#">Price: High to Low</a></li>
<li><a class="dropdown-item" href="#">Customer Rating</a></li>
<li><a class="dropdown-item" href="#">Newest Arrivals</a></li>
</ul>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary active">
<i class="fas fa-th"></i>
</button>
<button type="button" class="btn btn-outline-secondary">
<i class="fas fa-list"></i>
</button>
</div>
</div>
</div>
<!-- Product Cards -->
<div class="row">
<!-- Product Card 1 -->
<div class="col-xl-4 col-md-6 mb-4">
<div class="card product-card h-100 border-0 shadow-sm">
<div class="position-relative">
<img src="https://via.placeholder.com/300x300" class="card-img-top" alt="Product">
<div class="product-badges position-absolute top-0 start-0 p-2">
<span class="badge bg-danger">Sale</span>
<span class="badge bg-success">New</span>
</div>
<button class="btn btn-light btn-wishlist position-absolute top-0 end-0 m-2">
<i class="far fa-heart"></i>
</button>
</div>
<div class="card-body">
<div class="mb-2">
<span class="text-muted small">Electronics</span>
</div>
<h5 class="card-title">
<a href="#" class="text-decoration-none text-dark">Wireless Bluetooth Headphones</a>
</h5>
<div class="mb-2">
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star-half-alt text-warning"></i>
<span class="small text-muted ms-1">(4.5)</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="h5 mb-0">$99.99</span>
<span class="text-muted text-decoration-line-through ms-2">$129.99</span>
</div>
<button class="btn btn-primary btn-sm">
<i class="fas fa-shopping-cart me-1"></i> Add
</button>
</div>
</div>
</div>
</div>
<!-- Product Card 2 -->
<div class="col-xl-4 col-md-6 mb-4">
<div class="card product-card h-100 border-0 shadow-sm">
<div class="position-relative">
<img src="https://via.placeholder.com/300x300" class="card-img-top" alt="Product">
<button class="btn btn-light btn-wishlist position-absolute top-0 end-0 m-2">
<i class="far fa-heart"></i>
</button>
</div>
<div class="card-body">
<div class="mb-2">
<span class="text-muted small">Electronics</span>
</div>
<h5 class="card-title">
<a href="#" class="text-decoration-none text-dark">Smart Watch Series 5</a>
</h5>
<div class="mb-2">
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="fas fa-star text-warning"></i>
<i class="far fa-star text-warning"></i>
<span class="small text-muted ms-1">(4.0)</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="h5 mb-0">$249.99</span>
</div>
<button class="btn btn-primary btn-sm">
<i class="fas fa-shopping-cart me-1"></i> Add
</button>
</div>
</div>
</div>
</div>
<!-- More product cards would be here -->
</div>
<!-- Pagination -->
<nav aria-label="Page navigation" class="mt-5">
<ul class="pagination justify-content-center">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">Previous</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</section>
<!-- Featured Products -->
<section class="py-5 bg-light">
<div class="container">
<div class="text-center mb-5">
<h2 class="display-5 fw-bold">Featured Products</h2>
<p class="lead text-muted">Top picks from our collection</p>
</div>
<div class="row">
<!-- Featured product cards would be here -->
</div>
</div>
</section>
<!-- Footer -->
<footer class="bg-dark text-white py-5">
<div class="container">
<div class="row">
<div class="col-lg-3 col-md-6 mb-4">
<h5 class="mb-3">
<i class="fas fa-shopping-bag text-primary me-2"></i>ShopEasy
</h5>
<p>Your one-stop shop for all electronic needs. Quality products at competitive prices.</p>
<div class="d-flex gap-3 mt-4">
<a href="#" class="text-white-50"><i class="fab fa-facebook fa-lg"></i></a>
<a href="#" class="text-white-50"><i class="fab fa-twitter fa-lg"></i></a>
<a href="#" class="text-white-50"><i class="fab fa-instagram fa-lg"></i></a>
<a href="#" class="text-white-50"><i class="fab fa-youtube fa-lg"></i></a>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-4">
<h5 class="mb-3">Quick Links</h5>
<ul class="list-unstyled">
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Home</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Shop</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">About Us</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Contact</a></li>
</ul>
</div>
<div class="col-lg-3 col-md-6 mb-4">
<h5 class="mb-3">Customer Service</h5>
<ul class="list-unstyled">
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">FAQ</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Shipping Policy</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Returns & Refunds</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Privacy Policy</a></li>
</ul>
</div>
<div class="col-lg-3 col-md-6 mb-4">
<h5 class="mb-3">Newsletter</h5>
<p class="text-white-50">Subscribe to get special offers and updates.</p>
<div class="input-group mb-3">
<input type="email" class="form-control" placeholder="Your email">
<button class="btn btn-primary" type="button">Subscribe</button>
</div>
<p class="small text-white-50">By subscribing, you agree to our Privacy Policy.</p>
</div>
</div>
<hr class="my-4 text-white-50">
<div class="row">
<div class="col-md-6">
<p class="mb-0">© 2024 ShopEasy. All rights reserved.</p>
</div>
<div class="col-md-6 text-md-end">
<img src="https://via.placeholder.com/40" class="me-2" alt="Payment">
<img src="https://via.placeholder.com/40" class="me-2" alt="Payment">
<img src="https://via.placeholder.com/40" class="me-2" alt="Payment">
</div>
</div>
</div>
</footer>E-commerce Styling CSS
Custom E-commerce Styles
/* E-commerce Custom Styles */
:root {
--primary-color: #0d6efd;
--secondary-color: #6c757d;
--success-color: #198754;
--danger-color: #dc3545;
--warning-color: #ffc107;
--light-color: #f8f9fa;
--dark-color: #212529;
}
/* Product Cards */
.product-card {
transition: all 0.3s ease;
border-radius: 10px;
overflow: hidden;
}
.product-card:hover {
transform: translateY(-10px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1) !important;
}
.product-card img {
height: 250px;
object-fit: cover;
transition: transform 0.3s ease;
}
.product-card:hover img {
transform: scale(1.05);
}
.product-badges .badge {
margin-right: 5px;
font-size: 0.75rem;
padding: 0.25em 0.6em;
}
.btn-wishlist {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.btn-wishlist:hover {
background-color: var(--danger-color);
color: white;
}
.btn-wishlist.active {
background-color: var(--danger-color);
color: white;
}
.btn-wishlist.active i {
font-weight: 900;
}
/* Star Rating */
.star-rating {
color: var(--warning-color);
}
.star-rating .fa-star-half-alt {
position: relative;
}
.star-rating .fa-star-half-alt:before {
content: "\f005";
position: absolute;
left: 0;
width: 50%;
overflow: hidden;
}
/* Price Styling */
.price-current {
font-weight: bold;
color: var(--success-color);
}
.price-old {
text-decoration: line-through;
color: var(--secondary-color);
font-size: 0.9em;
}
/* Cart Badge */
.cart-badge {
font-size: 0.6em;
padding: 0.2em 0.5em;
position: absolute;
top: -8px;
right: -8px;
}
/* Filter Sidebar */
.filter-section {
border-bottom: 1px solid #dee2e6;
padding-bottom: 1rem;
margin-bottom: 1rem;
}
.filter-section:last-child {
border-bottom: none;
}
.form-range::-webkit-slider-thumb {
background-color: var(--primary-color);
}
.form-range::-moz-range-thumb {
background-color: var(--primary-color);
}
.form-check-input:checked {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
/* Product Grid View */
.grid-view .product-card {
height: 100%;
}
.list-view .product-card {
flex-direction: row;
height: auto;
}
.list-view .product-card img {
width: 200px;
height: 200px;
object-fit: cover;
}
.list-view .product-card .card-body {
flex: 1;
}
/* Shopping Cart */
.cart-item {
border-bottom: 1px solid #dee2e6;
padding: 1rem 0;
}
.cart-item:last-child {
border-bottom: none;
}
.quantity-input {
width: 70px;
text-align: center;
}
/* Checkout Steps */
.checkout-steps {
display: flex;
justify-content: space-between;
margin-bottom: 2rem;
position: relative;
}
.checkout-steps::before {
content: '';
position: absolute;
top: 20px;
left: 0;
right: 0;
height: 2px;
background-color: #dee2e6;
z-index: 1;
}
.checkout-step {
position: relative;
z-index: 2;
text-align: center;
flex: 1;
}
.step-number {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #dee2e6;
color: var(--secondary-color);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 0.5rem;
font-weight: bold;
}
.checkout-step.active .step-number {
background-color: var(--primary-color);
color: white;
}
.checkout-step.completed .step-number {
background-color: var(--success-color);
color: white;
}
/* Responsive Adjustments */
@media (max-width: 768px) {
.list-view .product-card {
flex-direction: column;
}
.list-view .product-card img {
width: 100%;
height: 250px;
}
.checkout-steps {
flex-direction: column;
gap: 1rem;
}
.checkout-steps::before {
display: none;
}
.checkout-step {
text-align: left;
display: flex;
align-items: center;
gap: 1rem;
}
.step-number {
margin: 0;
}
}
/* Animation for Add to Cart */
@keyframes addToCart {
0% {
transform: scale(1);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
.add-to-cart-animation {
animation: addToCart 0.3s ease;
}
/* Loading Spinner */
.loading-spinner {
display: inline-block;
width: 2rem;
height: 2rem;
border: 0.25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: spinner-border 0.75s linear infinite;
}
@keyframes spinner-border {
to { transform: rotate(360deg); }
}
/* Tooltips */
.tooltip-custom {
--bs-tooltip-bg: var(--dark-color);
--bs-tooltip-color: white;
}
/* Modal Styles */
.product-modal .modal-dialog {
max-width: 800px;
}
.product-gallery {
position: relative;
}
.product-thumbnails {
display: flex;
gap: 10px;
margin-top: 10px;
}
.product-thumbnail {
width: 80px;
height: 80px;
object-fit: cover;
cursor: pointer;
border: 2px solid transparent;
border-radius: 5px;
}
.product-thumbnail.active {
border-color: var(--primary-color);
}
/* Shipping Progress */
.shipping-progress {
height: 10px;
border-radius: 5px;
overflow: hidden;
}
.shipping-progress .progress-bar {
background-color: var(--success-color);
}
/* Discount Badge */
.discount-badge {
position: absolute;
top: 10px;
right: 10px;
background-color: var(--danger-color);
color: white;
padding: 5px 10px;
border-radius: 3px;
font-weight: bold;
font-size: 0.9em;
}
/* Product Variations */
.product-variations {
display: flex;
gap: 10px;
margin: 1rem 0;
}
.variation-option {
padding: 5px 15px;
border: 2px solid #dee2e6;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.variation-option:hover {
border-color: var(--primary-color);
}
.variation-option.active {
border-color: var(--primary-color);
background-color: var(--primary-color);
color: white;
}
/* Stock Status */
.in-stock {
color: var(--success-color);
font-weight: bold;
}
.low-stock {
color: var(--warning-color);
font-weight: bold;
}
.out-of-stock {
color: var(--danger-color);
font-weight: bold;
}
/* Order Summary */
.order-summary {
background-color: var(--light-color);
border-radius: 10px;
padding: 1.5rem;
}
.order-summary-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.order-summary-total {
border-top: 2px solid var(--dark-color);
padding-top: 1rem;
margin-top: 1rem;
font-weight: bold;
font-size: 1.2em;
}
/* Print Styles for Receipt */
@media print {
.no-print {
display: none !important;
}
.order-receipt {
font-size: 12px;
}
}E-commerce JavaScript Functionality
Interactive Features
// E-commerce JavaScript Functionality
class EcommerceStore {
constructor() {
this.cart = JSON.parse(localStorage.getItem('cart')) || [];
this.wishlist = JSON.parse(localStorage.getItem('wishlist')) || [];
this.init();
}
init() {
this.updateCartCount();
this.updateWishlistCount();
this.bindEvents();
this.loadProducts();
}
bindEvents() {
// Add to cart buttons
document.querySelectorAll('.add-to-cart').forEach(button => {
button.addEventListener('click', (e) => {
const product = this.getProductData(e.target);
this.addToCart(product);
this.showNotification('Added to cart!', 'success');
});
});
// Wishlist buttons
document.querySelectorAll('.btn-wishlist').forEach(button => {
button.addEventListener('click', (e) => {
const product = this.getProductData(e.target);
this.toggleWishlist(product);
e.target.classList.toggle('active');
e.target.querySelector('i').classList.toggle('far');
e.target.querySelector('i').classList.toggle('fas');
});
});
// Quantity controls
document.querySelectorAll('.quantity-control').forEach(control => {
control.addEventListener('click', (e) => {
const input = e.target.parentElement.querySelector('.quantity-input');
let value = parseInt(input.value);
if (e.target.classList.contains('quantity-up')) {
value++;
} else if (e.target.classList.contains('quantity-down') && value > 1) {
value--;
}
input.value = value;
this.updateCartItem(e.target.dataset.id, value);
});
});
// Remove from cart
document.querySelectorAll('.remove-from-cart').forEach(button => {
button.addEventListener('click', (e) => {
this.removeFromCart(e.target.dataset.id);
e.target.closest('.cart-item').remove();
});
});
// Filter products
document.querySelectorAll('.filter-option').forEach(option => {
option.addEventListener('change', () => {
this.filterProducts();
});
});
// Sort products
document.querySelector('#sortProducts').addEventListener('change', (e) => {
this.sortProducts(e.target.value);
});
// View toggle
document.querySelectorAll('.view-toggle').forEach(button => {
button.addEventListener('click', (e) => {
this.toggleView(e.target.dataset.view);
});
});
}
getProductData(element) {
const card = element.closest('.product-card');
return {
id: card.dataset.id,
name: card.querySelector('.product-name').textContent,
price: parseFloat(card.querySelector('.product-price').textContent.replace('$', '')),
image: card.querySelector('img').src,
quantity: 1
};
}
addToCart(product) {
const existingItem = this.cart.find(item => item.id === product.id);
if (existingItem) {
existingItem.quantity += product.quantity;
} else {
this.cart.push(product);
}
this.saveCart();
this.updateCartCount();
// Add animation
const button = document.querySelector(`[data-id="${product.id}"] .add-to-cart`);
if (button) {
button.classList.add('add-to-cart-animation');
setTimeout(() => button.classList.remove('add-to-cart-animation'), 300);
}
}
removeFromCart(productId) {
this.cart = this.cart.filter(item => item.id !== productId);
this.saveCart();
this.updateCartCount();
}
updateCartItem(productId, quantity) {
const item = this.cart.find(item => item.id === productId);
if (item) {
item.quantity = quantity;
this.saveCart();
this.updateCartTotal();
}
}
toggleWishlist(product) {
const index = this.wishlist.findIndex(item => item.id === product.id);
if (index > -1) {
this.wishlist.splice(index, 1);
} else {
this.wishlist.push(product);
}
localStorage.setItem('wishlist', JSON.stringify(this.wishlist));
this.updateWishlistCount();
}
saveCart() {
localStorage.setItem('cart', JSON.stringify(this.cart));
}
updateCartCount() {
const count = this.cart.reduce((total, item) => total + item.quantity, 0);
document.querySelectorAll('.cart-count').forEach(element => {
element.textContent = count;
element.style.display = count > 0 ? 'inline-block' : 'none';
});
this.updateCartTotal();
}
updateWishlistCount() {
const count = this.wishlist.length;
document.querySelectorAll('.wishlist-count').forEach(element => {
element.textContent = count;
element.style.display = count > 0 ? 'inline-block' : 'none';
});
}
updateCartTotal() {
const total = this.cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
document.querySelectorAll('.cart-total').forEach(element => {
element.textContent = `$${total.toFixed(2)}`;
});
}
filterProducts() {
const filters = {
category: Array.from(document.querySelectorAll('.category-filter:checked')).map(cb => cb.value),
brand: Array.from(document.querySelectorAll('.brand-filter:checked')).map(cb => cb.value),
minPrice: parseFloat(document.querySelector('#minPrice').value) || 0,
maxPrice: parseFloat(document.querySelector('#maxPrice').value) || 1000,
rating: document.querySelector('.rating-filter:checked')?.value || 0
};
const products = document.querySelectorAll('.product-card');
products.forEach(product => {
const productData = {
category: product.dataset.category,
brand: product.dataset.brand,
price: parseFloat(product.dataset.price),
rating: parseFloat(product.dataset.rating)
};
let show = true;
// Category filter
if (filters.category.length > 0 && !filters.category.includes(productData.category)) {
show = false;
}
// Brand filter
if (filters.brand.length > 0 && !filters.brand.includes(productData.brand)) {
show = false;
}
// Price filter
if (productData.price < filters.minPrice || productData.price > filters.maxPrice) {
show = false;
}
// Rating filter
if (productData.rating < filters.rating) {
show = false;
}
product.style.display = show ? 'block' : 'none';
});
}
sortProducts(sortBy) {
const container = document.querySelector('.products-container');
const products = Array.from(container.querySelectorAll('.product-card'));
products.sort((a, b) => {
const aData = {
price: parseFloat(a.dataset.price),
rating: parseFloat(a.dataset.rating),
date: new Date(a.dataset.date)
};
const bData = {
price: parseFloat(b.dataset.price),
rating: parseFloat(b.dataset.rating),
date: new Date(b.dataset.date)
};
switch (sortBy) {
case 'price-low':
return aData.price - bData.price;
case 'price-high':
return bData.price - aData.price;
case 'rating':
return bData.rating - aData.rating;
case 'newest':
return bData.date - aData.date;
default:
return 0;
}
});
// Reorder products
products.forEach(product => container.appendChild(product));
}
toggleView(viewType) {
const container = document.querySelector('.products-container');
container.className = `products-container ${viewType}-view`;
// Update active button
document.querySelectorAll('.view-toggle').forEach(button => {
button.classList.toggle('active', button.dataset.view === viewType);
});
}
loadProducts() {
// In a real app, this would fetch from an API
const products = [
// Product data would be here
];
this.renderProducts(products);
}
renderProducts(products) {
const container = document.querySelector('.products-container');
container.innerHTML = products.map(product => this.createProductCard(product)).join('');
}
createProductCard(product) {
return `
<div class="col-xl-4 col-md-6 mb-4" data-category="${product.category}" data-brand="${product.brand}" data-price="${product.price}" data-rating="${product.rating}">
<div class="card product-card h-100 border-0 shadow-sm">
<div class="position-relative">
<img src="${product.image}" class="card-img-top" alt="${product.name}">
${product.discount ? `<span class="badge bg-danger position-absolute top-0 start-0 m-2">${product.discount}% OFF</span>` : ''}
<button class="btn btn-light btn-wishlist position-absolute top-0 end-0 m-2 ${this.isInWishlist(product.id) ? 'active' : ''}">
<i class="${this.isInWishlist(product.id) ? 'fas' : 'far'} fa-heart"></i>
</button>
</div>
<div class="card-body">
<div class="mb-2">
<span class="text-muted small">${product.category}</span>
</div>
<h5 class="card-title">
<a href="#" class="text-decoration-none text-dark">${product.name}</a>
</h5>
<div class="mb-2">
${this.renderStars(product.rating)}
<span class="small text-muted ms-1">(${product.rating})</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="h5 mb-0">$${product.price.toFixed(2)}</span>
${product.originalPrice ? `<span class="text-muted text-decoration-line-through ms-2">$${product.originalPrice.toFixed(2)}</span>` : ''}
</div>
<button class="btn btn-primary btn-sm add-to-cart" data-id="${product.id}">
<i class="fas fa-shopping-cart me-1"></i> Add
</button>
</div>
</div>
</div>
</div>
`;
}
renderStars(rating) {
let stars = '';
for (let i = 1; i <= 5; i++) {
if (i <= Math.floor(rating)) {
stars += '<i class="fas fa-star text-warning"></i>';
} else if (i === Math.ceil(rating) && !Number.isInteger(rating)) {
stars += '<i class="fas fa-star-half-alt text-warning"></i>';
} else {
stars += '<i class="far fa-star text-warning"></i>';
}
}
return stars;
}
isInWishlist(productId) {
return this.wishlist.some(item => item.id === productId);
}
showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `alert alert-${type} alert-dismissible fade show position-fixed`;
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999;';
notification.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
checkout() {
// In a real app, this would process payment
const order = {
items: this.cart,
total: this.cart.reduce((sum, item) => sum + (item.price * item.quantity), 0),
date: new Date().toISOString(),
id: 'ORD-' + Math.random().toString(36).substr(2, 9).toUpperCase()
};
// Save order
const orders = JSON.parse(localStorage.getItem('orders')) || [];
orders.push(order);
localStorage.setItem('orders', JSON.stringify(orders));
// Clear cart
this.cart = [];
this.saveCart();
this.updateCartCount();
return order;
}
}
// Initialize store when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.store = new EcommerceStore();
// Initialize tooltips
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
// Initialize popovers
const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
popoverTriggerList.map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl));
});
// Export functionality for modules
export { EcommerceStore };E-commerce Features Overview
| Feature | Description | Components Used |
|---|---|---|
| Product Listing | Display products with images, prices, and ratings | Cards, Grid System, Badges, Buttons |
| Filtering System | Filter products by category, price, brand, rating | Checkboxes, Radio Buttons, Range Sliders |
| Sorting Options | Sort products by price, rating, date | Dropdowns, JavaScript Sorting |
| Shopping Cart | Add/remove items, quantity control, total calculation | LocalStorage, JavaScript Classes, Badges |
| Wishlist | Save favorite products for later | LocalStorage, Heart Icons, Badges |
| Product Details | Detailed product view with gallery and variations | Modals, Image Gallery, Tabs |
| Checkout Process | Multi-step checkout with forms and payment | Forms, Validation, Progress Steps |
| Order Management | View and track orders | Tables, Status Badges, Modals |
Responsive Design Strategy
Mobile View
- Single column product layout
- Hamburger menu for navigation
- Stacked filters in sidebar
- Simplified cart view
- Touch-friendly buttons
Tablet View
- Two-column product grid
- Collapsible sidebar filters
- Full navigation visible
- Enhanced cart dropdown
- Better image sizes
Desktop View
- Three-column product grid
- Permanent sidebar filters
- Advanced search functionality
- Detailed cart and wishlist
- Enhanced user experience
Payment Integration
Payment Methods Integration
- Credit/Debit Cards: Stripe, PayPal, Square integration
- Digital Wallets: Apple Pay, Google Pay, PayPal
- Bank Transfers: ACH, Wire transfers
- Cryptocurrency: Bitcoin, Ethereum payments
- Local Payments: Region-specific payment methods
- Subscription Payments: Recurring billing support
Security Considerations
E-commerce Security Best Practices
- Use HTTPS for all pages
- Implement CSRF protection
- Sanitize all user inputs
- Use secure payment gateways
- Implement rate limiting
- Secure user authentication
- Regular security audits
- PCI DSS compliance for payment processing