Q10. Design a Dynamic Website Demonstrating Web Technologies
Question 10:
Design a dynamic website using HTML, JavaScript, Bootstrap, and jQuery (no AngularJS).
Below is a compact, functional single-page e-commerce demo oriented to Indian products and prices (INR). It demonstrates:
- HTML5 structure & semantic elements
- Bootstrap 5 responsive layout & components
- jQuery + vanilla JS for DOM manipulation & events
- AJAX
try/catchto load product JSON with fallback - Cart operations (add, update qty, remove) and persistence (localStorage)
- Checkout form with client-side validation
Files
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
/>
<title>DesiStore — Demo E-Commerce (INR)</title>
<meta
name="description"
content="DesiStore demo e-commerce site built with HTML,
JS, Bootstrap 5 and jQuery. Cart, checkout, filters and INR currency."
/>
<!-- Bootstrap 5 -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- Optional: Bootstrap icons -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"
rel="stylesheet"
/>
<!-- Custom CSS -->
<link rel="stylesheet" href="styles.css" />
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body class="bg-light">
<!-- NAVBAR -->
<nav
class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm"
>
<div class="container">
<a class="navbar-brand fw-bold" href="#">DesiStore</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#nav"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="nav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#products">Products</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#contact">Contact</a>
</li>
</ul>
<form
class="d-flex me-3"
id="searchForm"
onsubmit="return false;"
>
<input
id="searchInput"
class="form-control form-control-sm"
type="search"
placeholder="Search products..."
aria-label="Search"
/>
</form>
<button
id="cartBtn"
class="btn btn-outline-light position-relative"
>
<i class="bi bi-cart3"></i> Cart
<span
id="cartCount"
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
>0</span
>
</button>
</div>
</div>
</nav>
<!-- HERO -->
<header class="py-5 text-white hero">
<div class="container text-center">
<h1 class="display-5 fw-bold">
DesiStore — Quality Goods, Local Prices
</h1>
<p class="lead">
A demo e-commerce site built with HTML, JavaScript,
Bootstrap & jQuery — prices shown in INR.
</p>
</div>
</header>
<!-- CONTROLS -->
<section class="container my-4">
<div
class="d-flex gap-2 flex-column flex-md-row align-items-start align-items-md-center"
>
<div class="me-auto">
<div class="btn-group" role="group" aria-label="categories">
<button
class="btn btn-outline-primary category-btn active"
data-cat="all"
>
All
</button>
<button
class="btn btn-outline-primary category-btn"
data-cat="electronics"
>
Electronics
</button>
<button
class="btn btn-outline-primary category-btn"
data-cat="fashion"
>
Fashion
</button>
<button
class="btn btn-outline-primary category-btn"
data-cat="home"
>
Home
</button>
<button
class="btn btn-outline-primary category-btn"
data-cat="books"
>
Books
</button>
</div>
</div>
<div class="d-flex gap-2">
<select id="sortSelect" class="form-select form-select-sm">
<option value="default">Sort: Featured</option>
<option value="price-asc">Price: Low to High</option>
<option value="price-desc">Price: High to Low</option>
<option value="name-asc">Name: A → Z</option>
</select>
<button id="refreshBtn" class="btn btn-sm btn-primary">
Refresh
</button>
</div>
</div>
</section>
<!-- PRODUCTS GRID -->
<main class="container mb-5" id="products">
<div id="productsRow" class="row g-4"></div>
</main>
<!-- CHECKOUT / CART OFFCANVAS -->
<div
class="offcanvas offcanvas-end"
tabindex="-1"
id="cartOffcanvas"
>
<div class="offcanvas-header">
<h5 class="offcanvas-title">Your Cart</h5>
<button
type="button"
class="btn-close text-reset"
data-bs-dismiss="offcanvas"
></button>
</div>
<div class="offcanvas-body d-flex flex-column">
<div id="cartItems" class="mb-3"></div>
<div class="mt-auto">
<div
class="d-flex justify-content-between align-items-center mb-3"
>
<strong>Total:</strong>
<h5 id="cartTotal" class="m-0">₹0.00</h5>
</div>
<button id="checkoutBtn" class="btn btn-success w-100 mb-2">
Checkout
</button>
<button
id="clearCartBtn"
class="btn btn-outline-danger w-100"
>
Clear Cart
</button>
</div>
</div>
</div>
<!-- CHECKOUT MODAL -->
<div class="modal fade" id="checkoutModal" tabindex="-1">
<div class="modal-dialog">
<form
id="checkoutForm"
class="modal-content needs-validation"
novalidate
>
<div class="modal-header">
<h5 class="modal-title">Checkout</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div id="orderSummary" class="mb-3"></div>
<div class="mb-3">
<label class="form-label">Full Name</label>
<input
type="text"
class="form-control"
id="custName"
required
/>
<div class="invalid-feedback">
Please enter your name.
</div>
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input
type="email"
class="form-control"
id="custEmail"
required
/>
<div class="invalid-feedback">
Please enter a valid email.
</div>
</div>
<div class="mb-3">
<label class="form-label">Phone</label>
<input
type="tel"
class="form-control"
id="custPhone"
pattern="[0-9]{10}"
required
/>
<div class="invalid-feedback">
Enter 10 digit phone number.
</div>
</div>
<div class="mb-3">
<label class="form-label">Address</label>
<textarea
id="custAddress"
class="form-control"
rows="2"
required
></textarea>
<div class="invalid-feedback">
Please enter shipping address.
</div>
</div>
<div class="form-text">
This is a demo checkout — payments are not processed.
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">
Place Order
</button>
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Cancel
</button>
</div>
</form>
</div>
</div>
<!-- Contact/Footer -->
<section id="contact" class="py-5 bg-white">
<div class="container text-center">
<h4>About Me</h4>
</div>
</section>
<section class="container py-5" style="min-height: 85vh;">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-3">
<div class="card-body text-center p-5">
<img
src="/img/profile.webp"
alt="Ansari Intesab"
class="rounded-circle mb-3"
width="150"
height="150"
/>
<h2 class="fw-bold mb-3">Ansari Intesab</h2>
<p class="lead text-muted">
I am a
<span class="fw-bold">Full-Stack Web Developer</span>
skilled in <strong>MERN Stack</strong>,
<strong>DevOps</strong>, <strong>PHP</strong>,
<strong>WordPress</strong>, and
<strong>Python</strong>. Passionate about building
modern, responsive web applications that solve
real-world problems.
</p>
<hr class="my-4" />
<h4 class="mb-3">Core Skills</h4>
<div class="row">
<div class="col-md-6 text-start">
<ul class="list-unstyled">
<li>MongoDB, Express, React, Node</li>
<li>DevOps & CI/CD Workflows</li>
<li>Mobile Apps</li>
</ul>
</div>
<div class="col-md-6 text-start">
<ul class="list-unstyled">
<li>PHP & Python Development</li>
<li>WordPress Themes & Plugins</li>
<li>Modern Web Security</li>
</ul>
</div>
</div>
<a
href="https://intesab.live"
target="_blank"
class="btn btn-primary btn-lg mt-4 shadow"
>
🌐 Visit My Portfolio
</a>
</div>
</div>
</div>
</div>
</section>
<footer class="py-3 bg-dark text-white text-center">
<div class="container">
© <span id="yr"></span> DesiStore — Demo by Ansari Intesab
</div>
</footer>
<!-- Bootstrap JS bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
<!-- App JS -->
<script src="app.js"></script>
</body>
</html>styles.css
/* Basic look */
body {
font-family:
'Inter',
system-ui,
-apple-system,
'Segoe UI',
Roboto,
'Helvetica Neue',
Arial;
color: #222;
}
/* Hero */
.hero {
background: linear-gradient(90deg, #007bff 0%, #00b4d8 100%);
padding-top: 3.5rem;
padding-bottom: 3.5rem;
color: #fff;
}
/* Product card style */
.product-card {
border-radius: 12px;
overflow: hidden;
border: 0;
transition:
transform 0.28s ease,
box-shadow 0.28s ease;
}
.product-card:hover {
transform: translateY(-6px);
box-shadow: 0 12px 30px rgba(2, 6, 23, 0.12);
}
.product-img {
height: 190px;
object-fit: cover;
width: 100%;
}
/* Price badge */
.price-tag {
display: inline-block;
background: linear-gradient(90deg, #ff9a9e, #fecfef);
color: #8b0000;
font-weight: 700;
padding: 6px 10px;
border-radius: 8px;
}
/* Small utilities */
.card-text {
color: #555;
font-size: 0.95rem;
}
.badge-cat {
text-transform: capitalize;
}
/* Cart offcanvas tweaks */
.offcanvas {
width: 420px;
max-width: 100%;
}
.offcanvas .btn {
border-radius: 8px;
}
/* Responsive tweaks */
@media (max-width: 576px) {
.product-img {
height: 150px;
}
}products.json
{
"products": [
{
"id": 1,
"title": "Smartphone — Nova X",
"category": "electronics",
"price": 12999,
"image": "https://via.placeholder.com/400x300?text=Smartphone"
},
{
"id": 2,
"title": "Men's Kurta Cotton",
"category": "fashion",
"price": 899,
"image": "https://via.placeholder.com/400x300?text=Kurta"
},
{
"id": 3,
"title": "LED TV 32 inch",
"category": "electronics",
"price": 15999,
"image": "https://via.placeholder.com/400x300?text=LED+TV"
},
{
"id": 4,
"title": "Non-Stick Cookware Set",
"category": "home",
"price": 2499,
"image": "https://via.placeholder.com/400x300?text=Cookware"
},
{
"id": 5,
"title": "Classic Novel Pack (3 books)",
"category": "books",
"price": 599,
"image": "https://via.placeholder.com/400x300?text=Books"
},
{
"id": 6,
"title": "Women's Ethnic Saree",
"category": "fashion",
"price": 1999,
"image": "https://via.placeholder.com/400x300?text=Saree"
},
{
"id": 7,
"title": "Bluetooth Headphones",
"category": "electronics",
"price": 2199,
"image": "https://via.placeholder.com/400x300?text=Headphones"
},
{
"id": 8,
"title": "Floor Lamp Modern",
"category": "home",
"price": 1299,
"image": "https://via.placeholder.com/400x300?text=Lamp"
}
]
}app.js (JS logic: load products, cart, checkout)
// Wait for DOM
$(function () {
const productsUrl = './products.json'; // try fetching JSON file
let products = [];
const $productsRow = $('#productsRow');
const cartKey = 'desistore_cart';
// Utility: format INR
function toINR(value) {
return value.toLocaleString('en-IN', {
style: 'currency',
currency: 'INR',
});
}
// Load products via AJAX with try/catch and fallback inline data
async function loadProducts() {
try {
const resp = await $.ajax({
url: productsUrl,
method: 'GET',
dataType: 'json',
cache: false,
});
products = resp.products || [];
} catch (err) {
console.warn(
'Failed loading products.json — using inline fallback',
err
);
// fallback inline products (same structure as products.json)
products = [
{
id: 1,
title: 'Smartphone — Nova X',
category: 'electronics',
price: 12999,
image: './img/Smartphone.webp',
},
{
id: 2,
title: "Men's Kurta Cotton",
category: 'fashion',
price: 899,
image: './img/mens.webp',
},
{
id: 3,
title: 'LED TV 32 inch',
category: 'electronics',
price: 15999,
image: './img/led.webp',
},
{
id: 4,
title: 'Non-Stick Cookware Set',
category: 'home',
price: 2499,
image: './img/nonstick.jpg',
},
{
id: 5,
title: 'Classic Novel Pack (3 books)',
category: 'books',
price: 599,
image: './img/3books.jpg',
},
{
id: 6,
title: "Women's Ethnic Saree",
category: 'fashion',
price: 1999,
image: './img/women.jpg',
},
{
id: 7,
title: 'Bluetooth Headphones',
category: 'electronics',
price: 2199,
image: './img/blue.jpg',
},
{
id: 8,
title: 'Floor Lamp Modern',
category: 'home',
price: 1299,
image: './img/lamp.webp',
},
];
}
renderProducts(products);
}
// Render product cards
function renderProducts(list) {
$productsRow.empty();
if (!list.length) {
$productsRow.html(
'<div class="col-12 text-center py-5"><h5 class="text-muted">No products found</h5></div>'
);
return;
}
list.forEach((p) => {
const col = $(`
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card product-card h-100">
<img src="${p.image}" class="product-img card-img-top" alt="${p.title}" onerror="this.onerror=null;this.src='https://via.placeholder.com/400x300?text=Image';">
<div class="card-body d-flex flex-column">
<small class="badge bg-secondary badge-cat mb-2">${p.category}</small>
<h6 class="card-title">${p.title}</h6>
<p class="card-text mb-2">${toINR(p.price)}</p>
<div class="mt-auto">
<button class="btn btn-primary w-100 add-to-cart" data-id="${p.id}"><i class="bi bi-cart-plus"></i> Add to Cart</button>
</div>
</div>
</div>
</div>
`);
$productsRow.append(col);
});
}
// CART helpers
function loadCart() {
try {
return JSON.parse(localStorage.getItem(cartKey)) || {};
} catch (e) {
return {};
}
}
function saveCart(cart) {
localStorage.setItem(cartKey, JSON.stringify(cart));
updateCartCount();
}
function updateCartCount() {
const cart = loadCart();
const count = Object.values(cart).reduce((s, i) => s + i.qty, 0);
$('#cartCount').text(count);
}
function renderCart() {
const cart = loadCart();
const $cartItems = $('#cartItems');
$cartItems.empty();
let total = 0;
if (!Object.keys(cart).length) {
$cartItems.html(
'<p class="text-muted">Your cart is empty.</p>'
);
} else {
Object.values(cart).forEach((item) => {
total += item.qty * item.price;
const row = $(`
<div class="d-flex align-items-center mb-3">
<img src="${item.image}" style="width:60px;height:45px;object-fit:cover;border-radius:8px;margin-right:10px">
<div class="flex-fill">
<div class="small text-muted">${item.title}</div>
<div><strong>${toINR(item.price)}</strong> x
<input type="number" min="1" value="${item.qty}" data-id="${item.id}" class="form-control form-control-sm d-inline-block ms-1 qty-input" style="width:72px;">
<button class="btn btn-sm btn-link text-danger remove-item" data-id="${item.id}">Remove</button>
</div>
</div>
</div>
`);
$cartItems.append(row);
});
}
$('#cartTotal').text(toINR(total));
$('#orderSummary').html(
`<p><strong>Items:</strong> ${Object.keys(cart).length} • <strong>Total:</strong> ${toINR(total)}</p>`
);
}
// Add to cart handler (delegated)
$(document).on('click', '.add-to-cart', function () {
const id = $(this).data('id');
const product = products.find((p) => p.id === id);
if (!product) return;
const cart = loadCart();
if (!cart[id])
cart[id] = {
id: product.id,
title: product.title,
price: product.price,
qty: 0,
image: product.image,
};
cart[id].qty += 1;
saveCart(cart);
renderCart();
// open offcanvas
const offcanvas = new bootstrap.Offcanvas($('#cartOffcanvas')[0]);
offcanvas.show();
});
// Cart quantity change
$(document).on('change', '.qty-input', function () {
const id = $(this).data('id');
const val = parseInt($(this).val(), 10) || 1;
const cart = loadCart();
if (cart[id]) {
cart[id].qty = val;
saveCart(cart);
renderCart();
}
});
// Remove item
$(document).on('click', '.remove-item', function () {
const id = $(this).data('id');
const cart = loadCart();
delete cart[id];
saveCart(cart);
renderCart();
});
// Cart button open
$('#cartBtn').on('click', function () {
renderCart();
const offcanvas = new bootstrap.Offcanvas($('#cartOffcanvas')[0]);
offcanvas.show();
});
// Clear cart
$('#clearCartBtn').on('click', function () {
if (!confirm('Clear cart?')) return;
localStorage.removeItem(cartKey);
renderCart();
updateCartCount();
});
// Checkout
$('#checkoutBtn').on('click', function () {
const cart = loadCart();
if (!Object.keys(cart).length) {
alert('Cart is empty.');
return;
}
renderCart();
const modal = new bootstrap.Modal($('#checkoutModal'));
modal.show();
});
// Submit checkout form with validation
$('#checkoutForm').on('submit', function (e) {
e.preventDefault();
const form = this;
if (!form.checkValidity()) {
form.classList.add('was-validated');
return;
}
// simulate order placement
try {
const cart = loadCart();
const order = {
items: cart,
total: $('#cartTotal').text(),
customer: {
name: $('#custName').val(),
email: $('#custEmail').val(),
phone: $('#custPhone').val(),
address: $('#custAddress').val(),
},
createdAt: new Date().toISOString(),
};
// In real app: send order via AJAX to server
console.log('Order placed (demo):', order);
// clear cart and close modal/offcanvas
localStorage.removeItem(cartKey);
updateCartCount();
$('#cartOffcanvas').removeClass('show'); // hide offcanvas if open
const bsModal = bootstrap.Modal.getInstance(
$('#checkoutModal')[0]
);
bsModal.hide();
alert(
'Order placed! (Demo) — check console for order details.'
);
} catch (err) {
console.error('Checkout error:', err);
alert('Something went wrong during checkout.');
}
});
// Search & filter & sort
$('#searchInput').on('input', function () {
const q = $(this).val().trim().toLowerCase();
filterSortSearch(
q,
$('.category-btn.active').data('cat'),
$('#sortSelect').val()
);
});
$('.category-btn').on('click', function () {
$('.category-btn').removeClass('active');
$(this).addClass('active');
filterSortSearch(
$('#searchInput').val().trim().toLowerCase(),
$(this).data('cat'),
$('#sortSelect').val()
);
});
$('#sortSelect').on('change', function () {
filterSortSearch(
$('#searchInput').val().trim().toLowerCase(),
$('.category-btn.active').data('cat'),
$(this).val()
);
});
$('#refreshBtn').on('click', function () {
loadProducts();
});
// Generic filter + sort + search pipeline
function filterSortSearch(q, cat, sort) {
let list = [...products];
if (cat && cat !== 'all')
list = list.filter((p) => p.category === cat);
if (q)
list = list.filter((p) =>
(p.title + ' ' + p.category).toLowerCase().includes(q)
);
if (sort === 'price-asc') list.sort((a, b) => a.price - b.price);
else if (sort === 'price-desc')
list.sort((a, b) => b.price - a.price);
else if (sort === 'name-asc')
list.sort((a, b) => a.title.localeCompare(b.title));
renderProducts(list);
}
// Initialize
$('#yr').text(new Date().getFullYear());
loadProducts();
updateCartCount();
});Output Preview : DesiStore
How to use / Integrate
- Put these 4 files in one folder and open
index.htmlin browser (for local AJAXproducts.json, use a local server — e.g.,npx http-serveror VSCode Live Server). - Or host on your Node/Express app’s
public/folder and visit the route. - Add/modify
products.jsonfor more items. The app uses AJAXtry/catchso ifproducts.jsonis missing the inline fallback still shows products.
Notes (for grading / write-up)
-
Why this demonstrates web technologies:
- HTML5: semantic sections, forms, structure.
- CSS & Bootstrap 5: responsive layout and components.
- JavaScript + jQuery: DOM updates, events, AJAX, try/catch fallback.
- Client-side persistence:
localStoragefor cart. - Simple checkout validation demonstrates interactive web UX.
-
SEO tip: use descriptive
<title>,<meta description>, product pages (if you expand to per-product pages) should includecanonicaland uniquemetatags.
Last updated on