Pages Easy
Wishlist Page
An e-commerce wishlist / saved items page with product cards, move-to-cart action, remove button, share wishlist, and empty state. No libraries.
Open in Lab
MCP
vanilla-js css
Targets: JS HTML
Code
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #f3f4f6;
color: #1f2937;
line-height: 1.5;
min-height: 100vh;
}
.wishlist-container {
max-width: 900px;
margin: 0 auto;
padding: 32px 20px;
}
/* โโ Header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.wishlist-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
flex-wrap: wrap;
gap: 16px;
margin-bottom: 24px;
}
.wishlist-header-left {
display: flex;
align-items: baseline;
gap: 12px;
}
.wishlist-title {
font-size: 28px;
font-weight: 700;
color: #111827;
}
.wishlist-count {
font-size: 14px;
color: #6b7280;
background: #e5e7eb;
padding: 2px 10px;
border-radius: 12px;
font-weight: 500;
}
.wishlist-header-right {
display: flex;
align-items: center;
gap: 12px;
}
.wishlist-sort {
display: flex;
align-items: center;
gap: 6px;
}
.wishlist-sort label {
font-size: 13px;
color: #6b7280;
white-space: nowrap;
}
.wishlist-sort select {
font-size: 13px;
padding: 6px 28px 6px 10px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: #fff
url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
no-repeat right 10px center;
appearance: none;
cursor: pointer;
color: #374151;
}
.wishlist-sort select:focus {
outline: none;
border-color: #6366f1;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
}
.btn-share {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
font-size: 13px;
font-weight: 500;
color: #374151;
background: #fff;
border: 1px solid #d1d5db;
border-radius: 8px;
cursor: pointer;
transition: all 0.15s;
}
.btn-share:hover {
background: #f9fafb;
border-color: #9ca3af;
}
/* โโ Wishlist Cards โโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.wishlist-items {
display: flex;
flex-direction: column;
gap: 12px;
}
.wishlist-card {
display: flex;
align-items: center;
gap: 20px;
background: #fff;
border-radius: 12px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
border-left: 4px solid #6366f1;
transition: transform 0.2s, box-shadow 0.2s, opacity 0.3s;
}
.wishlist-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.wishlist-card.removing {
opacity: 0;
transform: translateX(-20px);
}
.card-image {
width: 120px;
height: 120px;
border-radius: 10px;
flex-shrink: 0;
}
.card-details {
flex: 1;
min-width: 0;
}
.card-title {
font-size: 16px;
font-weight: 600;
color: #111827;
margin-bottom: 6px;
}
.card-price {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.price-current {
font-size: 18px;
font-weight: 700;
color: #111827;
}
.price-sale {
color: #dc2626;
}
.price-original {
font-size: 14px;
color: #9ca3af;
text-decoration: line-through;
}
.stock-badge {
display: inline-block;
font-size: 11px;
font-weight: 600;
padding: 2px 8px;
border-radius: 10px;
text-transform: uppercase;
letter-spacing: 0.3px;
}
.stock-in {
background: #dcfce7;
color: #16a34a;
}
.stock-low {
background: #fef3c7;
color: #d97706;
}
.stock-out {
background: #fee2e2;
color: #dc2626;
}
.card-date {
font-size: 12px;
color: #9ca3af;
margin-top: 6px;
}
/* โโ Card Actions โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.card-actions {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.btn-heart {
width: 36px;
height: 36px;
border-radius: 50%;
border: none;
background: #fee2e2;
color: #ef4444;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: transform 0.15s, background 0.15s;
}
.btn-heart:hover {
transform: scale(1.1);
}
.btn-heart.active {
background: #fee2e2;
color: #ef4444;
}
.btn-heart:not(.active) {
background: #f3f4f6;
color: #9ca3af;
}
.btn-heart:not(.active) svg {
fill: none;
}
.btn-cart {
padding: 8px 16px;
font-size: 13px;
font-weight: 500;
color: #6366f1;
background: transparent;
border: 1.5px solid #6366f1;
border-radius: 8px;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
}
.btn-cart:hover:not(:disabled) {
background: #6366f1;
color: #fff;
}
.btn-cart:disabled {
color: #9ca3af;
border-color: #d1d5db;
cursor: not-allowed;
}
.btn-cart.in-cart {
background: #dcfce7;
color: #16a34a;
border-color: #16a34a;
cursor: default;
}
.btn-remove {
width: 28px;
height: 28px;
border-radius: 6px;
border: none;
background: transparent;
color: #9ca3af;
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s;
}
.btn-remove:hover {
background: #fee2e2;
color: #ef4444;
}
/* โโ Empty State โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.wishlist-empty {
text-align: center;
padding: 80px 20px;
}
.empty-icon {
margin-bottom: 20px;
}
.empty-title {
font-size: 22px;
font-weight: 600;
color: #374151;
margin-bottom: 8px;
}
.empty-text {
font-size: 15px;
color: #9ca3af;
margin-bottom: 24px;
}
.btn-browse {
padding: 12px 28px;
font-size: 14px;
font-weight: 600;
color: #fff;
background: #6366f1;
border: none;
border-radius: 10px;
cursor: pointer;
transition: background 0.15s;
}
.btn-browse:hover {
background: #4f46e5;
}
/* โโ Toast โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.toast {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%) translateY(80px);
background: #1f2937;
color: #fff;
padding: 12px 24px;
border-radius: 10px;
font-size: 14px;
font-weight: 500;
opacity: 0;
transition: transform 0.3s, opacity 0.3s;
pointer-events: none;
z-index: 1000;
white-space: nowrap;
}
.toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* โโ Responsive โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
@media (max-width: 640px) {
.wishlist-header {
flex-direction: column;
align-items: flex-start;
}
.wishlist-header-right {
flex-wrap: wrap;
}
.wishlist-card {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.card-image {
width: 100%;
height: 160px;
}
.card-actions {
flex-direction: row;
width: 100%;
justify-content: flex-end;
}
}(function () {
const itemsContainer = document.getElementById("wishlistItems");
const emptyState = document.getElementById("wishlistEmpty");
const countEl = document.getElementById("wishlistCount");
const sortSelect = document.getElementById("sortSelect");
const shareBtn = document.getElementById("shareBtn");
const toast = document.getElementById("toast");
let toastTimer = null;
function showToast(message) {
toast.textContent = message;
toast.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toast.classList.remove("show");
}, 2500);
}
function updateCount() {
var cards = itemsContainer.querySelectorAll(".wishlist-card");
var n = cards.length;
countEl.textContent = n + (n === 1 ? " item" : " items");
if (n === 0) {
itemsContainer.style.display = "none";
emptyState.style.display = "block";
}
}
function removeCard(card) {
card.classList.add("removing");
setTimeout(function () {
card.remove();
updateCount();
}, 300);
}
itemsContainer.addEventListener("click", function (e) {
var card = e.target.closest(".wishlist-card");
if (!card) return;
// Remove button (x)
if (e.target.closest(".btn-remove")) {
removeCard(card);
showToast("Item removed from wishlist");
return;
}
// Heart toggle
var heartBtn = e.target.closest(".btn-heart");
if (heartBtn) {
if (heartBtn.classList.contains("active")) {
heartBtn.classList.remove("active");
showToast("Item will be removed");
setTimeout(function () {
removeCard(card);
}, 600);
} else {
heartBtn.classList.add("active");
}
return;
}
// Move to cart
var cartBtn = e.target.closest(".btn-cart");
if (cartBtn && !cartBtn.disabled && !cartBtn.classList.contains("in-cart")) {
cartBtn.classList.add("in-cart");
cartBtn.textContent = "In Cart \u2713";
showToast("Added to cart");
return;
}
});
// Sort
sortSelect.addEventListener("change", function () {
var cards = Array.from(itemsContainer.querySelectorAll(".wishlist-card"));
var val = sortSelect.value;
cards.sort(function (a, b) {
if (val === "date-desc") {
return b.dataset.date.localeCompare(a.dataset.date);
}
if (val === "date-asc") {
return a.dataset.date.localeCompare(b.dataset.date);
}
if (val === "price-low") {
return parseFloat(a.dataset.price) - parseFloat(b.dataset.price);
}
if (val === "price-high") {
return parseFloat(b.dataset.price) - parseFloat(a.dataset.price);
}
if (val === "name-az") {
return a.dataset.name.localeCompare(b.dataset.name);
}
return 0;
});
cards.forEach(function (card) {
itemsContainer.appendChild(card);
});
});
// Share
shareBtn.addEventListener("click", function () {
var url = window.location.href;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(url).then(function () {
showToast("Wishlist link copied to clipboard");
});
} else {
var input = document.createElement("input");
input.value = url;
document.body.appendChild(input);
input.select();
document.execCommand("copy");
document.body.removeChild(input);
showToast("Wishlist link copied to clipboard");
}
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Wishlist</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wishlist-container">
<header class="wishlist-header">
<div class="wishlist-header-left">
<h1 class="wishlist-title">My Wishlist</h1>
<span class="wishlist-count" id="wishlistCount">6 items</span>
</div>
<div class="wishlist-header-right">
<div class="wishlist-sort">
<label for="sortSelect">Sort by:</label>
<select id="sortSelect">
<option value="date-desc">Date Added (Newest)</option>
<option value="date-asc">Date Added (Oldest)</option>
<option value="price-low">Price: Low to High</option>
<option value="price-high">Price: High to Low</option>
<option value="name-az">Name: A to Z</option>
</select>
</div>
<button class="btn-share" id="shareBtn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/>
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/>
</svg>
Share Wishlist
</button>
</div>
</header>
<div class="wishlist-items" id="wishlistItems">
<div class="wishlist-card" data-price="89.99" data-date="2026-03-15" data-name="Wireless Noise-Cancelling Headphones">
<div class="card-image" style="background: linear-gradient(135deg, #667eea, #764ba2);"></div>
<div class="card-details">
<h3 class="card-title">Wireless Noise-Cancelling Headphones</h3>
<div class="card-price">
<span class="price-current">$89.99</span>
</div>
<span class="stock-badge stock-in">In Stock</span>
<p class="card-date">Added on March 15, 2026</p>
</div>
<div class="card-actions">
<button class="btn-heart active" title="Remove from wishlist">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
<button class="btn-cart">Move to Cart</button>
<button class="btn-remove" title="Remove item">×</button>
</div>
</div>
<div class="wishlist-card" data-price="129.00" data-date="2026-03-14" data-name="Ergonomic Office Chair">
<div class="card-image" style="background: linear-gradient(135deg, #f093fb, #f5576c);"></div>
<div class="card-details">
<h3 class="card-title">Ergonomic Office Chair</h3>
<div class="card-price">
<span class="price-original">$179.00</span>
<span class="price-current price-sale">$129.00</span>
</div>
<span class="stock-badge stock-in">In Stock</span>
<p class="card-date">Added on March 14, 2026</p>
</div>
<div class="card-actions">
<button class="btn-heart active" title="Remove from wishlist">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
<button class="btn-cart">Move to Cart</button>
<button class="btn-remove" title="Remove item">×</button>
</div>
</div>
<div class="wishlist-card" data-price="34.50" data-date="2026-03-12" data-name="Bamboo Desk Organizer">
<div class="card-image" style="background: linear-gradient(135deg, #4facfe, #00f2fe);"></div>
<div class="card-details">
<h3 class="card-title">Bamboo Desk Organizer</h3>
<div class="card-price">
<span class="price-current">$34.50</span>
</div>
<span class="stock-badge stock-low">Low Stock</span>
<p class="card-date">Added on March 12, 2026</p>
</div>
<div class="card-actions">
<button class="btn-heart active" title="Remove from wishlist">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
<button class="btn-cart">Move to Cart</button>
<button class="btn-remove" title="Remove item">×</button>
</div>
</div>
<div class="wishlist-card" data-price="249.99" data-date="2026-03-10" data-name="Mechanical Keyboard RGB">
<div class="card-image" style="background: linear-gradient(135deg, #43e97b, #38f9d7);"></div>
<div class="card-details">
<h3 class="card-title">Mechanical Keyboard RGB</h3>
<div class="card-price">
<span class="price-original">$299.99</span>
<span class="price-current price-sale">$249.99</span>
</div>
<span class="stock-badge stock-in">In Stock</span>
<p class="card-date">Added on March 10, 2026</p>
</div>
<div class="card-actions">
<button class="btn-heart active" title="Remove from wishlist">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
<button class="btn-cart">Move to Cart</button>
<button class="btn-remove" title="Remove item">×</button>
</div>
</div>
<div class="wishlist-card" data-price="59.00" data-date="2026-03-08" data-name="Ultrawide Mouse Pad">
<div class="card-image" style="background: linear-gradient(135deg, #fa709a, #fee140);"></div>
<div class="card-details">
<h3 class="card-title">Ultrawide Mouse Pad</h3>
<div class="card-price">
<span class="price-current">$59.00</span>
</div>
<span class="stock-badge stock-out">Out of Stock</span>
<p class="card-date">Added on March 8, 2026</p>
</div>
<div class="card-actions">
<button class="btn-heart active" title="Remove from wishlist">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
<button class="btn-cart" disabled>Out of Stock</button>
<button class="btn-remove" title="Remove item">×</button>
</div>
</div>
<div class="wishlist-card" data-price="42.00" data-date="2026-03-05" data-name="LED Monitor Light Bar">
<div class="card-image" style="background: linear-gradient(135deg, #a18cd1, #fbc2eb);"></div>
<div class="card-details">
<h3 class="card-title">LED Monitor Light Bar</h3>
<div class="card-price">
<span class="price-current">$42.00</span>
</div>
<span class="stock-badge stock-in">In Stock</span>
<p class="card-date">Added on March 5, 2026</p>
</div>
<div class="card-actions">
<button class="btn-heart active" title="Remove from wishlist">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
<button class="btn-cart">Move to Cart</button>
<button class="btn-remove" title="Remove item">×</button>
</div>
</div>
</div>
<div class="wishlist-empty" id="wishlistEmpty" style="display: none;">
<div class="empty-icon">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#9ca3af" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</div>
<h2 class="empty-title">Your wishlist is empty</h2>
<p class="empty-text">Start browsing to save items you love</p>
<button class="btn-browse">Browse Products</button>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="script.js"></script>
</body>
</html>Wishlist Page
A saved items / wishlist page for e-commerce. Shows favorited products with options to move to cart, remove, or share the entire wishlist.
Features
- Product list โ cards with image, title, price, stock status, date added
- Actions โ Move to Cart button, Remove (heart toggle) button per item
- Share wishlist โ copy link or share buttons
- Sort by โ Date Added, Price, Name
- Empty state โ โYour wishlist is emptyโ with CTA to browse products
- Item count โ โ6 saved itemsโ
When to use it
- E-commerce wishlist page
- Saved items / bookmarks page
- Favorite products list