JavaScript UI Kit
Reusable UI components
JavaScript localStorage is one of the most useful browser features for saving small pieces of data directly inside a visitor’s browser. It can be used for form drafts, shopping carts, dark mode preferences, saved filters, recently viewed products, favorite items, user settings, notes, quiz progress, dashboard widgets, and many other interactive website features that should remember something after the page reloads.
In this guide, you will find 30 JavaScript localStorage examples for real website projects, including saved form data, persistent shopping carts, dark mode settings, product favorites, recently viewed items, saved search filters, tab preferences, accordion states, draft notes, to-do lists, mini CRM notes, quiz progress, price calculator history, cookie-style banners, and reusable vanilla JavaScript storage components.
This post focuses on practical JavaScript localStorage logic, including localStorage.setItem(), localStorage.getItem(), localStorage.removeItem(), JSON storage, arrays, objects, form state, browser persistence, reset buttons, UI updates, and copy-paste-ready HTML, CSS, and JavaScript examples. For related JavaScript UI components, you can also explore our JavaScript form validation examples, JavaScript search filter examples, JavaScript dropdown menu examples, and JavaScript countdown timer examples.
JavaScript localStorage is a browser storage feature that lets websites save small pieces of data on the user’s device. Unlike temporary JavaScript variables, localStorage data can stay available after the page reloads, after the browser tab closes, and after the visitor returns later.
The main purpose of localStorage is to remember simple user data in the browser without needing a database for every small interaction. For example, a website can remember a visitor’s dark mode preference, a partially completed form, selected filters, favorite products, dismissed banners, cart items, or the last active tab in a content section.
LocalStorage is especially useful for front-end demos, UI components, small tools, ecommerce prototypes, landing pages, dashboards, and WordPress custom HTML blocks where you want a simple persistent browser feature. It is not a replacement for secure server-side storage, but it is very useful for interface state, preferences, and non-sensitive data.
LocalStorage matters because many modern websites need to remember small actions. A visitor may expect their form draft to stay available after refresh, their selected theme to stay active, their cart to stay visible, or their filters to remain selected while browsing a product list.
LocalStorage should still be used carefully. It is best for non-sensitive browser data. You should not store passwords, private tokens, payment details, personal identity numbers, or confidential data in localStorage. For simple UI memory, saved preferences, carts, drafts, and browser-based examples, it is one of the easiest JavaScript features to learn and use.
There are many practical localStorage use cases for websites and web apps. Some are small interface improvements, while others can feel like complete mini applications. The key is to store the right amount of data and update the interface whenever the saved data changes.
A simple localStorage feature may save one value, such as a dark mode setting. A more advanced feature may save an array of cart products, an object with user preferences, a list of saved notes, multi-step form progress, or filter settings that rebuild the UI when the page loads again.
This guide focuses on JavaScript localStorage examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, easy to customize, and different in layout, purpose, storage logic, UI behavior, and responsive design.
A good localStorage feature should be useful, predictable, and easy to reset. Users should understand what is being saved, the interface should update immediately after changes, and the saved data should load correctly when the page opens again.
The feature should have a clear reason to save data, such as a form draft, cart, preference, favorite item, note, or progress state.
The saved value should appear again after refresh, and the UI should match what is stored in the browser.
LocalStorage should be used for non-sensitive data only. Private, secure, or payment-related information belongs on the server.
Users should be able to clear saved drafts, remove cart items, reset preferences, or delete stored browser data when needed.
Before building a localStorage feature, decide exactly what should be saved and what should happen when the visitor returns. Should the form refill automatically? Should the cart rebuild itself? Should the selected tab reopen? Should the user see a “clear saved data” button? These small decisions make the difference between a basic demo and a professional JavaScript component.
You can combine JavaScript localStorage with many other website UI patterns. Saved form drafts work well with modern CSS forms, persistent carts can support ecommerce layouts and modern CSS pricing tables, saved tabs can be used with modern CSS tabs, and preference panels can fit inside layouts from our modern CSS layouts guide.
Now let’s look at 30 JavaScript localStorage examples for real website projects. Each example uses a different storage purpose, layout style, interface pattern, saved data structure, browser persistence behavior, reset option, form logic, cart logic, preference setting, or responsive UI approach, so you can build useful browser-based features with visible JavaScript, HTML, and CSS code.
An auto-save contact form draft is one of the most practical JavaScript localStorage examples. It helps users keep their typed message, name, email, and project details even if they accidentally refresh the page or leave the browser tab.
This example saves form fields automatically while the visitor types. When the page loads again, JavaScript reads the saved values from localStorage and restores the form. The user can also clear the saved draft with one button.
This form saves your draft in the browser while you type. Refresh the page and the values will still be there.
(function () {
const wrapper = document.querySelector("[data-vb-storage-one]");
if (!wrapper) return;
const storageKey = "vbStorageOneContactDraft";
const form = wrapper.querySelector(".vb-storage-one-form");
const status = wrapper.querySelector("[data-status]");
const savedTime = wrapper.querySelector("[data-saved-time]");
const clearButton = wrapper.querySelector("[data-clear]");
const fields = {
name: form.elements.name,
email: form.elements.email,
project: form.elements.project,
message: form.elements.message
};
function getDraftData() {
return {
name: fields.name.value,
email: fields.email.value,
project: fields.project.value,
message: fields.message.value,
savedAt: new Date().toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit"
})
};
}
function saveDraft() {
const draft = getDraftData();
localStorage.setItem(storageKey, JSON.stringify(draft));
status.textContent = "Draft status: saved in this browser";
savedTime.textContent = "Last saved at " + draft.savedAt;
}
function loadDraft() {
const savedDraft = localStorage.getItem(storageKey);
if (!savedDraft) return;
try {
const draft = JSON.parse(savedDraft);
fields.name.value = draft.name || "";
fields.email.value = draft.email || "";
fields.project.value = draft.project || "";
fields.message.value = draft.message || "";
status.textContent = "Draft status: restored from localStorage";
savedTime.textContent = draft.savedAt
? "Restored draft saved at " + draft.savedAt
: "Restored saved draft";
} catch (error) {
localStorage.removeItem(storageKey);
status.textContent = "Draft status: saved data was reset";
}
}
function clearDraft() {
localStorage.removeItem(storageKey);
form.reset();
status.textContent = "Draft status: cleared";
savedTime.textContent = "No saved draft yet";
}
Object.values(fields).forEach(function (field) {
field.addEventListener("input", saveDraft);
field.addEventListener("change", saveDraft);
});
clearButton.addEventListener("click", clearDraft);
loadDraft();
})();
<div class="vb-storage-one-demo">
<div class="vb-storage-one-card" data-vb-storage-one>
<div class="vb-storage-one-info">
<span class="vb-storage-one-kicker">Example 01</span>
<h3>Saved Contact Draft</h3>
<p>This form saves your draft in the browser while you type. Refresh the page and the values will still be there.</p>
<div class="vb-storage-one-status" data-status>
Draft status: waiting for input
</div>
</div>
<form class="vb-storage-one-form">
<label>
<span>Your name</span>
<input type="text" name="name" placeholder="Alex Morgan">
</label>
<label>
<span>Email address</span>
<input type="email" name="email" placeholder="alex@example.com">
</label>
<label>
<span>Project type</span>
<select name="project">
<option value="">Choose project type</option>
<option value="Website design">Website design</option>
<option value="WordPress plugin">WordPress plugin</option>
<option value="Ecommerce store">Ecommerce store</option>
<option value="JavaScript feature">JavaScript feature</option>
</select>
</label>
<label>
<span>Project message</span>
<textarea name="message" rows="5" placeholder="Tell us what you want to build..."></textarea>
</label>
<div class="vb-storage-one-actions">
<button type="button" data-clear>Clear Saved Draft</button>
<span data-saved-time>No saved draft yet</span>
</div>
</form>
</div>
</div>
.vb-storage-one-demo,
.vb-storage-one-demo * {
box-sizing: border-box;
}
.vb-storage-one-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 34px;
background:
radial-gradient(circle at 16% 12%, rgba(59, 130, 246, 0.18), transparent 34%),
radial-gradient(circle at 86% 20%, rgba(16, 185, 129, 0.18), transparent 36%),
linear-gradient(135deg, #eff6ff 0%, #f0fdfa 55%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}
.vb-storage-one-card {
display: grid;
grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
gap: clamp(22px, 4vw, 34px);
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 28px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}
.vb-storage-one-info {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 0;
}
.vb-storage-one-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 18px;
padding: 8px 12px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-one-info h3 {
margin: 0 0 16px !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 68px) !important;
line-height: 0.94 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-one-info p {
max-width: 520px;
margin: 0 0 22px !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.75;
font-weight: 650;
}
.vb-storage-one-status {
display: inline-flex;
align-self: flex-start;
padding: 13px 15px;
border-radius: 18px;
background: #ecfdf5;
border: 1px solid rgba(16, 185, 129, 0.24);
color: #047857 !important;
-webkit-text-fill-color: #047857 !important;
font-size: 14px;
line-height: 1.45;
font-weight: 850;
}
.vb-storage-one-form {
display: grid;
gap: 14px;
min-width: 0;
padding: clamp(18px, 3vw, 24px);
border-radius: 24px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-one-form label {
display: grid;
gap: 7px;
}
.vb-storage-one-form label span {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-one-form input,
.vb-storage-one-form select,
.vb-storage-one-form textarea {
width: 100%;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #ffffff;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
font-weight: 650;
outline: none;
box-shadow: none;
}
.vb-storage-one-form input,
.vb-storage-one-form select {
min-height: 48px;
padding: 0 14px;
}
.vb-storage-one-form textarea {
resize: vertical;
padding: 13px 14px;
line-height: 1.55;
}
.vb-storage-one-form input:focus,
.vb-storage-one-form select:focus,
.vb-storage-one-form textarea:focus {
border-color: rgba(37, 99, 235, 0.76);
box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}
.vb-storage-one-actions {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
margin-top: 2px;
}
.vb-storage-one-actions button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
padding: 11px 15px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #2563eb, #06b6d4);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
box-shadow: 0 14px 34px rgba(37, 99, 235, 0.22);
}
.vb-storage-one-actions span {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 13px;
font-weight: 750;
}
@media (max-width: 880px) {
.vb-storage-one-card {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-one-card {
padding: 18px;
border-radius: 22px;
}
.vb-storage-one-info h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-one-actions button {
width: 100%;
}
}
This localStorage form draft example is useful for contact pages, lead generation forms, quote request forms, support forms, onboarding forms, and long message fields where users should not lose their progress after a page refresh.
A localStorage shopping cart is a great way to learn how browser storage works with arrays, objects, buttons, totals, and dynamic UI rendering. It can store cart items in the browser without a backend, making it useful for demos, prototypes, and small front-end ecommerce examples.
This example lets users add products to a mini cart, increase or decrease quantities, remove items, clear the cart, and keep the cart saved after refresh. JavaScript stores the cart as a JSON array in localStorage and rebuilds the cart interface on page load.
Add products to the cart, refresh the page, and the selected items will still be saved in localStorage.
Reusable UI components
Useful frontend features
Structured data starter
Your cart is empty.
(function () {
const wrapper = document.querySelector("[data-vb-storage-two]");
if (!wrapper) return;
const storageKey = "vbStorageTwoMiniCart";
const addButtons = wrapper.querySelectorAll("[data-add-cart]");
const cartList = wrapper.querySelector("[data-cart-list]");
const cartCount = wrapper.querySelector("[data-cart-count]");
const cartTotal = wrapper.querySelector("[data-cart-total]");
const clearCartButton = wrapper.querySelector("[data-clear-cart]");
let cart = [];
function saveCart() {
localStorage.setItem(storageKey, JSON.stringify(cart));
}
function loadCart() {
const savedCart = localStorage.getItem(storageKey);
if (!savedCart) return;
try {
const parsedCart = JSON.parse(savedCart);
cart = Array.isArray(parsedCart) ? parsedCart : [];
} catch (error) {
cart = [];
localStorage.removeItem(storageKey);
}
}
function getTotalItems() {
return cart.reduce(function (sum, item) {
return sum + item.quantity;
}, 0);
}
function getTotalPrice() {
return cart.reduce(function (sum, item) {
return sum + item.price * item.quantity;
}, 0);
}
function renderCart() {
cartList.innerHTML = "";
if (cart.length === 0) {
cartList.innerHTML = '<p class="vb-storage-two-empty">Your cart is empty.</p>';
} else {
cart.forEach(function (item) {
const cartItem = document.createElement("div");
cartItem.className = "vb-storage-two-cart-item";
cartItem.innerHTML =
'<div>' +
'<h5>' + item.name + '</h5>' +
'<p>' + item.price + '€ each</p>' +
'</div>' +
'<div class="vb-storage-two-qty">' +
'<button type="button" data-decrease="' + item.id + '">-</button>' +
'<span>' + item.quantity + '</span>' +
'<button type="button" data-increase="' + item.id + '">+</button>' +
'</div>';
cartList.appendChild(cartItem);
});
}
const totalItems = getTotalItems();
cartCount.textContent = totalItems === 1 ? "1 item" : totalItems + " items";
cartTotal.textContent = getTotalPrice() + "€";
}
function addToCart(product) {
const existingItem = cart.find(function (item) {
return item.id === product.id;
});
if (existingItem) {
existingItem.quantity += 1;
} else {
cart.push({
id: product.id,
name: product.name,
price: product.price,
quantity: 1
});
}
saveCart();
renderCart();
}
function changeQuantity(productId, direction) {
const item = cart.find(function (cartItem) {
return cartItem.id === productId;
});
if (!item) return;
item.quantity += direction;
if (item.quantity <= 0) {
cart = cart.filter(function (cartItem) {
return cartItem.id !== productId;
});
}
saveCart();
renderCart();
}
addButtons.forEach(function (button) {
button.addEventListener("click", function () {
addToCart({
id: button.getAttribute("data-id"),
name: button.getAttribute("data-name"),
price: Number(button.getAttribute("data-price"))
});
});
});
cartList.addEventListener("click", function (event) {
const increaseId = event.target.getAttribute("data-increase");
const decreaseId = event.target.getAttribute("data-decrease");
if (increaseId) {
changeQuantity(increaseId, 1);
}
if (decreaseId) {
changeQuantity(decreaseId, -1);
}
});
clearCartButton.addEventListener("click", function () {
cart = [];
saveCart();
renderCart();
});
loadCart();
renderCart();
})();
<div class="vb-storage-two-demo">
<div class="vb-storage-two-shop" data-vb-storage-two>
<div class="vb-storage-two-header">
<span class="vb-storage-two-kicker">Example 02</span>
<h3>Persistent Mini Cart</h3>
<p>Add products to the cart, refresh the page, and the selected items will still be saved in localStorage.</p>
</div>
<div class="vb-storage-two-layout">
<div class="vb-storage-two-products">
<article class="vb-storage-two-product">
<div class="vb-storage-two-product-icon">JS</div>
<div>
<h4>JavaScript UI Kit</h4>
<p>Reusable UI components</p>
</div>
<strong>29€</strong>
<button type="button" data-add-cart data-id="ui-kit" data-name="JavaScript UI Kit" data-price="29">Add</button>
</article>
<article class="vb-storage-two-product">
<div class="vb-storage-two-product-icon">WP</div>
<div>
<h4>WordPress Snippet Pack</h4>
<p>Useful frontend features</p>
</div>
<strong>39€</strong>
<button type="button" data-add-cart data-id="wp-pack" data-name="WordPress Snippet Pack" data-price="39">Add</button>
</article>
<article class="vb-storage-two-product">
<div class="vb-storage-two-product-icon">SEO</div>
<div>
<h4>SEO Schema Template</h4>
<p>Structured data starter</p>
</div>
<strong>19€</strong>
<button type="button" data-add-cart data-id="schema-template" data-name="SEO Schema Template" data-price="19">Add</button>
</article>
</div>
<div class="vb-storage-two-cart">
<div class="vb-storage-two-cart-head">
<strong>Your Cart</strong>
<span data-cart-count>0 items</span>
</div>
<div class="vb-storage-two-cart-list" data-cart-list>
<p class="vb-storage-two-empty">Your cart is empty.</p>
</div>
<div class="vb-storage-two-total">
<span>Total</span>
<strong data-cart-total>0€</strong>
</div>
<button class="vb-storage-two-clear" type="button" data-clear-cart>Clear Cart</button>
</div>
</div>
</div>
</div>
.vb-storage-two-demo,
.vb-storage-two-demo * {
box-sizing: border-box;
}
.vb-storage-two-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 42px;
background:
radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
radial-gradient(circle at 88% 14%, rgba(168, 85, 247, 0.18), transparent 34%),
linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
border: 1px solid rgba(99, 102, 241, 0.18);
box-shadow: 0 28px 80px rgba(79, 70, 229, 0.10);
}
.vb-storage-two-shop {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #0f172a;
overflow: hidden;
box-shadow: 0 28px 90px rgba(15, 23, 42, 0.28);
}
.vb-storage-two-header {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-two-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(255,255,255,0.10);
border: 1px solid rgba(255,255,255,0.14);
color: #bfdbfe !important;
-webkit-text-fill-color: #bfdbfe !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-two-header h3 {
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-two-header p {
max-width: 720px;
margin: 0 !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-two-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(310px, 390px);
gap: 20px;
align-items: start;
}
.vb-storage-two-products {
display: grid;
gap: 14px;
}
.vb-storage-two-product {
display: grid;
grid-template-columns: 64px minmax(0, 1fr) auto auto;
gap: 14px;
align-items: center;
min-width: 0;
padding: 16px;
border-radius: 24px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-two-product-icon {
display: grid;
place-items: center;
width: 64px;
height: 64px;
border-radius: 20px;
background: linear-gradient(135deg, #2563eb, #7c3aed);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 17px;
font-weight: 950;
}
.vb-storage-two-product h4 {
margin: 0 0 5px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 17px !important;
line-height: 1.2 !important;
font-weight: 900 !important;
}
.vb-storage-two-product p {
margin: 0 !important;
color: #94a3b8 !important;
-webkit-text-fill-color: #94a3b8 !important;
font-size: 13px;
font-weight: 650;
}
.vb-storage-two-product strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 19px;
font-weight: 950;
white-space: nowrap;
}
.vb-storage-two-product button,
.vb-storage-two-clear {
border: 0;
cursor: pointer;
font-weight: 950;
}
.vb-storage-two-product button {
min-height: 42px;
padding: 10px 14px;
border-radius: 999px;
background: #ffffff;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 13px;
}
.vb-storage-two-cart {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 26px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.20);
box-shadow: 0 20px 60px rgba(2, 6, 23, 0.20);
}
.vb-storage-two-cart-head,
.vb-storage-two-total {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-two-cart-head strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 22px;
font-weight: 950;
}
.vb-storage-two-cart-head span {
color: #2563eb !important;
-webkit-text-fill-color: #2563eb !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-two-cart-list {
display: grid;
gap: 10px;
min-height: 110px;
}
.vb-storage-two-empty {
display: grid;
place-items: center;
min-height: 110px;
margin: 0 !important;
border: 1px dashed rgba(148, 163, 184, 0.55);
border-radius: 18px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-two-cart-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
align-items: center;
padding: 12px;
border-radius: 18px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-two-cart-item h5 {
margin: 0 0 4px !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 14px !important;
line-height: 1.2 !important;
font-weight: 900 !important;
}
.vb-storage-two-cart-item p {
margin: 0 !important;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 750;
}
.vb-storage-two-qty {
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.vb-storage-two-qty button {
display: grid;
place-items: center;
width: 28px;
height: 28px;
border: 0;
border-radius: 999px;
background: #e0e7ff;
color: #3730a3 !important;
-webkit-text-fill-color: #3730a3 !important;
font-size: 16px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-two-qty span {
min-width: 24px;
text-align: center;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-two-total {
padding: 14px;
border-radius: 18px;
background: #eff6ff;
}
.vb-storage-two-total span {
color: #1e3a8a !important;
-webkit-text-fill-color: #1e3a8a !important;
font-size: 13px;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-two-total strong {
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 26px;
line-height: 1;
font-weight: 950;
}
.vb-storage-two-clear {
min-height: 44px;
border-radius: 999px;
background: linear-gradient(135deg, #2563eb, #7c3aed);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
}
@media (max-width: 980px) {
.vb-storage-two-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 680px) {
.vb-storage-two-product {
grid-template-columns: 54px minmax(0, 1fr);
}
.vb-storage-two-product strong,
.vb-storage-two-product button {
grid-column: 2;
justify-self: start;
}
.vb-storage-two-product-icon {
width: 54px;
height: 54px;
border-radius: 17px;
}
}
This localStorage shopping cart example is useful for ecommerce prototypes, product landing pages, mini carts, digital product pages, simple checkout demos, and JavaScript projects that need persistent cart state without a backend.
A dark mode preference saved with localStorage lets visitors choose their preferred interface style and keep that choice after refreshing or returning to the page later. This is one of the most common and useful localStorage patterns for modern websites.
This example uses a polished settings card with light mode, dark mode, and system-style buttons. JavaScript saves the selected theme name in localStorage, updates the demo instantly, and restores the same theme when the page loads again.
Your theme preference is stored locally in the browser, so this dashboard remembers the selected look.
(function () {
const app = document.querySelector("[data-vb-storage-three]");
if (!app) return;
const storageKey = "vbStorageThreeTheme";
const buttons = app.querySelectorAll("[data-theme-button]");
const currentTheme = app.querySelector("[data-current-theme]");
const settingLabel = app.querySelector("[data-setting-label]");
function formatThemeName(theme) {
return theme.charAt(0).toUpperCase() + theme.slice(1);
}
function applyTheme(theme) {
app.setAttribute("data-theme", theme);
currentTheme.textContent = formatThemeName(theme);
settingLabel.textContent = "theme: " + theme;
buttons.forEach(function (button) {
const isActive = button.getAttribute("data-theme-button") === theme;
button.classList.toggle("is-active", isActive);
});
}
function saveTheme(theme) {
localStorage.setItem(storageKey, theme);
applyTheme(theme);
}
buttons.forEach(function (button) {
button.addEventListener("click", function () {
const selectedTheme = button.getAttribute("data-theme-button");
saveTheme(selectedTheme);
});
});
const savedTheme = localStorage.getItem(storageKey) || "soft";
applyTheme(savedTheme);
})();
<div class="vb-storage-three-demo">
<div class="vb-storage-three-app" data-vb-storage-three data-theme="soft">
<div class="vb-storage-three-sidebar">
<span class="vb-storage-three-kicker">Example 03</span>
<h3>Saved Theme Preference</h3>
<p>Choose a theme and refresh the page. The selected style is saved in localStorage and restored automatically.</p>
<div class="vb-storage-three-buttons" role="group" aria-label="Theme preference buttons">
<button type="button" data-theme-button="light">Light</button>
<button type="button" data-theme-button="dark">Dark</button>
<button type="button" data-theme-button="soft">Soft</button>
</div>
<div class="vb-storage-three-current">
Current theme: <strong data-current-theme>Soft</strong>
</div>
</div>
<div class="vb-storage-three-panel">
<div class="vb-storage-three-topbar">
<span></span>
<span></span>
<span></span>
</div>
<div class="vb-storage-three-content">
<div class="vb-storage-three-avatar">UI</div>
<div>
<h4>Dashboard Appearance</h4>
<p>Your theme preference is stored locally in the browser, so this dashboard remembers the selected look.</p>
</div>
</div>
<div class="vb-storage-three-metrics">
<div>
<span>Saved setting</span>
<strong data-setting-label>theme: soft</strong>
</div>
<div>
<span>Storage type</span>
<strong>localStorage</strong>
</div>
</div>
</div>
</div>
</div>
.vb-storage-three-demo,
.vb-storage-three-demo * {
box-sizing: border-box;
}
.vb-storage-three-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 22px 54px 22px 54px;
background:
linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
linear-gradient(0deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
background-size: 26px 26px, 26px 26px, auto !important;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}
.vb-storage-three-app {
display: grid;
grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
gap: 22px;
max-width: 1140px;
margin: 0 auto;
padding: clamp(18px, 4vw, 30px);
border-radius: 18px 42px 18px 42px;
transition: background 0.25s ease, color 0.25s ease;
}
.vb-storage-three-app[data-theme="light"] {
background: #ffffff;
color: #0f172a;
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}
.vb-storage-three-app[data-theme="dark"] {
background: #0f172a;
color: #ffffff;
box-shadow: 0 24px 70px rgba(2, 6, 23, 0.34);
}
.vb-storage-three-app[data-theme="soft"] {
background: linear-gradient(135deg, #eef2ff, #ecfdf5);
color: #0f172a;
box-shadow: 0 24px 70px rgba(79, 70, 229, 0.14);
}
.vb-storage-three-sidebar,
.vb-storage-three-panel {
min-width: 0;
}
.vb-storage-three-sidebar {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 28px);
border-radius: 18px 34px 18px 34px;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar {
background: #f8fafc;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar {
background: rgba(255,255,255,0.07);
}
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar {
background: rgba(255,255,255,0.72);
}
.vb-storage-three-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-kicker {
background: rgba(96, 165, 250, 0.18);
color: #bfdbfe !important;
-webkit-text-fill-color: #bfdbfe !important;
}
.vb-storage-three-sidebar h3 {
margin: 0 0 16px !important;
font-size: clamp(35px, 5.8vw, 66px) !important;
line-height: 0.95 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar h3,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar h3 {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar h3 {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-three-sidebar p {
max-width: 520px;
margin: 0 0 22px !important;
font-size: 16px;
line-height: 1.75;
font-weight: 650;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar p,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar p {
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar p {
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
}
.vb-storage-three-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 18px;
}
.vb-storage-three-buttons button {
min-height: 44px;
padding: 10px 15px;
border: 0;
border-radius: 999px;
background: #2563eb;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
box-shadow: 0 14px 34px rgba(37, 99, 235, 0.20);
}
.vb-storage-three-buttons button.is-active {
background: linear-gradient(135deg, #10b981, #06b6d4);
}
.vb-storage-three-current {
display: inline-flex;
align-self: flex-start;
padding: 12px 14px;
border-radius: 16px;
font-size: 14px;
font-weight: 850;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-current,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-current {
background: #ffffff;
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-current {
background: rgba(255,255,255,0.09);
color: #e2e8f0 !important;
-webkit-text-fill-color: #e2e8f0 !important;
}
.vb-storage-three-current strong {
margin-left: 5px;
}
.vb-storage-three-panel {
display: grid;
gap: 18px;
align-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 34px 12px 34px 12px;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-panel {
background: #eff6ff;
border: 1px solid rgba(37, 99, 235, 0.16);
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-panel {
background: rgba(255,255,255,0.07);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-panel {
background: rgba(255,255,255,0.76);
border: 1px solid rgba(255,255,255,0.72);
}
.vb-storage-three-topbar {
display: flex;
gap: 8px;
}
.vb-storage-three-topbar span {
width: 12px;
height: 12px;
border-radius: 999px;
background: #60a5fa;
}
.vb-storage-three-topbar span:nth-child(2) {
background: #34d399;
}
.vb-storage-three-topbar span:nth-child(3) {
background: #a78bfa;
}
.vb-storage-three-content {
display: grid;
grid-template-columns: 78px minmax(0, 1fr);
gap: 18px;
align-items: center;
padding: 22px;
border-radius: 26px;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-content,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content {
background: #ffffff;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content {
background: rgba(15, 23, 42, 0.70);
}
.vb-storage-three-avatar {
display: grid;
place-items: center;
width: 78px;
height: 78px;
border-radius: 24px;
background: linear-gradient(135deg, #2563eb, #10b981);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 22px;
font-weight: 950;
}
.vb-storage-three-content h4 {
margin: 0 0 8px !important;
font-size: clamp(22px, 3vw, 32px) !important;
line-height: 1.1 !important;
font-weight: 950 !important;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-content h4,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content h4 {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content h4 {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-three-content p {
margin: 0 !important;
font-size: 15px;
line-height: 1.65;
font-weight: 650;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-content p,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content p {
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content p {
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
}
.vb-storage-three-metrics {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.vb-storage-three-metrics div {
padding: 16px;
border-radius: 22px;
}
.vb-storage-three-app[data-theme="light"] .vb-storage-three-metrics div,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-metrics div {
background: #ffffff;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-metrics div {
background: rgba(15, 23, 42, 0.70);
}
.vb-storage-three-metrics span {
display: block;
margin-bottom: 7px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-three-metrics strong {
color: #2563eb !important;
-webkit-text-fill-color: #2563eb !important;
font-size: 18px;
line-height: 1.2;
font-weight: 950;
}
.vb-storage-three-app[data-theme="dark"] .vb-storage-three-metrics strong {
color: #93c5fd !important;
-webkit-text-fill-color: #93c5fd !important;
}
@media (max-width: 900px) {
.vb-storage-three-app {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-three-content {
grid-template-columns: 1fr;
}
.vb-storage-three-metrics {
grid-template-columns: 1fr;
}
.vb-storage-three-sidebar h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This dark mode localStorage example is useful for dashboards, blogs, SaaS apps, user account pages, admin panels, documentation websites, and any interface where users should be able to keep their preferred visual theme.
A recently viewed products section is a very practical localStorage feature for ecommerce websites, product catalogs, affiliate sites, digital product shops, and WooCommerce-style layouts. It helps visitors return to products they checked earlier without needing a backend system.
This example lets users click product cards and stores the latest viewed products in localStorage. The recently viewed list updates instantly, avoids duplicates, keeps the newest product first, and restores the same list after page refresh.
Click a product card. The recently viewed list is saved in localStorage and restored after refresh.
(function () {
const wrapper = document.querySelector("[data-vb-storage-four]");
if (!wrapper) return;
const storageKey = "vbStorageFourRecentlyViewed";
const productButtons = wrapper.querySelectorAll("[data-view-product]");
const recentList = wrapper.querySelector("[data-recent-list]");
const clearButton = wrapper.querySelector("[data-clear-recent]");
let recentlyViewed = [];
function saveRecentlyViewed() {
localStorage.setItem(storageKey, JSON.stringify(recentlyViewed));
}
function loadRecentlyViewed() {
const savedItems = localStorage.getItem(storageKey);
if (!savedItems) return;
try {
const parsedItems = JSON.parse(savedItems);
recentlyViewed = Array.isArray(parsedItems) ? parsedItems : [];
} catch (error) {
recentlyViewed = [];
localStorage.removeItem(storageKey);
}
}
function renderRecentlyViewed() {
recentList.innerHTML = "";
if (recentlyViewed.length === 0) {
recentList.innerHTML = '<p class="vb-storage-four-empty">No products viewed yet.</p>';
return;
}
recentlyViewed.forEach(function (product) {
const item = document.createElement("div");
item.className = "vb-storage-four-recent-item";
item.innerHTML =
'<div class="vb-storage-four-recent-icon">' + product.shortLabel + '</div>' +
'<div>' +
'<strong>' + product.name + '</strong>' +
'<span>' + product.category + ' · ' + product.price + '</span>' +
'</div>';
recentList.appendChild(item);
});
}
function addViewedProduct(product) {
recentlyViewed = recentlyViewed.filter(function (item) {
return item.id !== product.id;
});
recentlyViewed.unshift(product);
recentlyViewed = recentlyViewed.slice(0, 4);
saveRecentlyViewed();
renderRecentlyViewed();
}
productButtons.forEach(function (button) {
button.addEventListener("click", function () {
const product = {
id: button.getAttribute("data-id"),
name: button.getAttribute("data-name"),
category: button.getAttribute("data-category"),
price: button.getAttribute("data-price"),
shortLabel: button.querySelector(".vb-storage-four-visual").textContent
};
addViewedProduct(product);
});
});
clearButton.addEventListener("click", function () {
recentlyViewed = [];
saveRecentlyViewed();
renderRecentlyViewed();
});
loadRecentlyViewed();
renderRecentlyViewed();
})();
<div class="vb-storage-four-demo">
<div class="vb-storage-four-shop" data-vb-storage-four>
<div class="vb-storage-four-intro">
<span class="vb-storage-four-kicker">Example 04</span>
<h3>Recently Viewed Products</h3>
<p>Click a product card. The recently viewed list is saved in localStorage and restored after refresh.</p>
</div>
<div class="vb-storage-four-grid">
<div class="vb-storage-four-products">
<button type="button" class="vb-storage-four-product" data-view-product data-id="greenhouse-kit" data-name="Greenhouse Starter Kit" data-category="Garden" data-price="249€">
<span class="vb-storage-four-visual">GH</span>
<strong>Greenhouse Starter Kit</strong>
<small>Garden · 249€</small>
</button>
<button type="button" class="vb-storage-four-product" data-view-product data-id="seo-plugin" data-name="SEO Schema Plugin" data-category="WordPress" data-price="29€">
<span class="vb-storage-four-visual">SEO</span>
<strong>SEO Schema Plugin</strong>
<small>WordPress · 29€</small>
</button>
<button type="button" class="vb-storage-four-product" data-view-product data-id="ui-template" data-name="Landing Page UI Template" data-category="Design" data-price="19€">
<span class="vb-storage-four-visual">UI</span>
<strong>Landing Page UI Template</strong>
<small>Design · 19€</small>
</button>
<button type="button" class="vb-storage-four-product" data-view-product data-id="cart-script" data-name="Mini Cart JavaScript" data-category="JavaScript" data-price="15€">
<span class="vb-storage-four-visual">JS</span>
<strong>Mini Cart JavaScript</strong>
<small>JavaScript · 15€</small>
</button>
</div>
<aside class="vb-storage-four-sidebar">
<div class="vb-storage-four-sidebar-head">
<strong>Recently Viewed</strong>
<button type="button" data-clear-recent>Clear</button>
</div>
<div class="vb-storage-four-list" data-recent-list>
<p class="vb-storage-four-empty">No products viewed yet.</p>
</div>
</aside>
</div>
</div>
</div>
.vb-storage-four-demo,
.vb-storage-four-demo * {
box-sizing: border-box;
}
.vb-storage-four-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 42px;
background:
radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
linear-gradient(135deg, #f0fdf4 0%, #f8fafc 58%, #ffffff 100%) !important;
border: 1px solid rgba(34, 197, 94, 0.18);
box-shadow: 0 28px 80px rgba(22, 101, 52, 0.10);
}
.vb-storage-four-shop {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.20);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-four-intro {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-four-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #dcfce7;
color: #15803d !important;
-webkit-text-fill-color: #15803d !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-four-intro h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-four-intro p {
max-width: 740px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-four-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
gap: 20px;
align-items: start;
}
.vb-storage-four-products {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-four-product {
display: grid;
gap: 12px;
min-width: 0;
padding: 18px;
border: 1px solid rgba(148, 163, 184, 0.22);
border-radius: 26px;
background: #f8fafc;
text-align: left;
cursor: pointer;
transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}
.vb-storage-four-product:hover {
transform: translateY(-3px);
border-color: rgba(34, 197, 94, 0.50);
box-shadow: 0 18px 44px rgba(15, 23, 42, 0.10);
}
.vb-storage-four-visual {
display: grid;
place-items: center;
width: 68px;
height: 68px;
border-radius: 22px;
background: linear-gradient(135deg, #22c55e, #0ea5e9);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 18px;
font-weight: 950;
}
.vb-storage-four-product strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 18px;
line-height: 1.2;
font-weight: 950;
}
.vb-storage-four-product small {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 13px;
font-weight: 750;
}
.vb-storage-four-sidebar {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #0f172a;
box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}
.vb-storage-four-sidebar-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-four-sidebar-head strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 22px;
font-weight: 950;
}
.vb-storage-four-sidebar-head button {
min-height: 36px;
padding: 8px 12px;
border: 0;
border-radius: 999px;
background: rgba(255,255,255,0.12);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 12px;
font-weight: 900;
cursor: pointer;
}
.vb-storage-four-list {
display: grid;
gap: 10px;
min-height: 220px;
}
.vb-storage-four-empty {
display: grid;
place-items: center;
min-height: 220px;
margin: 0 !important;
border: 1px dashed rgba(255,255,255,0.22);
border-radius: 20px;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-four-recent-item {
display: grid;
grid-template-columns: 52px minmax(0, 1fr);
gap: 12px;
align-items: center;
padding: 12px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-four-recent-icon {
display: grid;
place-items: center;
width: 52px;
height: 52px;
border-radius: 16px;
background: linear-gradient(135deg, #22c55e, #0ea5e9);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-four-recent-item strong {
display: block;
margin-bottom: 5px;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
line-height: 1.2;
font-weight: 900;
}
.vb-storage-four-recent-item span {
color: #a7f3d0 !important;
-webkit-text-fill-color: #a7f3d0 !important;
font-size: 12px;
font-weight: 800;
}
@media (max-width: 940px) {
.vb-storage-four-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-four-products {
grid-template-columns: 1fr;
}
.vb-storage-four-intro h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This recently viewed products localStorage example is useful for ecommerce stores, WooCommerce product pages, affiliate product roundups, comparison websites, product directories, and catalog-style landing pages.
Saved search filters are useful for product directories, blog archives, job boards, real estate listings, service pages, SaaS dashboards, course libraries, and any interface where users filter a list. LocalStorage can remember the selected search text, category, price range, or sorting option after refresh.
This example uses a small resource directory with search, category filter, and sort options. JavaScript saves the selected filter state in localStorage, restores it when the page loads again, and updates the visible results automatically.
Search, filter, sort, refresh the page, and your selected directory filters will stay saved in localStorage.
Save form data, carts, preferences, and UI state in the browser.
Build lightweight WordPress plugins with custom frontend features.
Improve structured data, internal links, and AI-readable content.
Create searchable and filterable user interfaces with vanilla JavaScript.
Improve product cards, checkout flows, quote forms, and mini carts.
Add useful structured data to long-form SEO content and guides.
(function () {
const wrapper = document.querySelector("[data-vb-storage-five]");
if (!wrapper) return;
const storageKey = "vbStorageFiveFilters";
const searchInput = wrapper.querySelector("[data-search]");
const categorySelect = wrapper.querySelector("[data-category]");
const sortSelect = wrapper.querySelector("[data-sort]");
const resetButton = wrapper.querySelector("[data-reset-filters]");
const resultCount = wrapper.querySelector("[data-result-count]");
const filterStatus = wrapper.querySelector("[data-filter-status]");
const resultsContainer = wrapper.querySelector("[data-results]");
const items = Array.from(wrapper.querySelectorAll("[data-item]"));
function getFilterState() {
return {
search: searchInput.value.trim().toLowerCase(),
category: categorySelect.value,
sort: sortSelect.value
};
}
function saveFilterState() {
localStorage.setItem(storageKey, JSON.stringify(getFilterState()));
}
function loadFilterState() {
const savedState = localStorage.getItem(storageKey);
if (!savedState) return;
try {
const state = JSON.parse(savedState);
searchInput.value = state.search || "";
categorySelect.value = state.category || "all";
sortSelect.value = state.sort || "popular";
} catch (error) {
localStorage.removeItem(storageKey);
}
}
function sortItems(itemsToSort, sortType) {
return itemsToSort.slice().sort(function (a, b) {
if (sortType === "az") {
return a.dataset.title.localeCompare(b.dataset.title);
}
if (sortType === "newest") {
return new Date(b.dataset.date) - new Date(a.dataset.date);
}
return Number(b.dataset.popularity) - Number(a.dataset.popularity);
});
}
function updateResults() {
const state = getFilterState();
const sortedItems = sortItems(items, state.sort);
let visibleCount = 0;
sortedItems.forEach(function (item) {
resultsContainer.appendChild(item);
const title = item.dataset.title.toLowerCase();
const category = item.dataset.category;
const matchesSearch = title.includes(state.search);
const matchesCategory = state.category === "all" || category === state.category;
const isVisible = matchesSearch && matchesCategory;
item.classList.toggle("is-hidden", !isVisible);
if (isVisible) {
visibleCount += 1;
}
});
resultCount.textContent = visibleCount === 1 ? "1 result" : visibleCount + " results";
filterStatus.textContent = "Saved filter: " + (state.category === "all" ? "all categories" : state.category) + " · " + state.sort;
saveFilterState();
}
function resetFilters() {
searchInput.value = "";
categorySelect.value = "all";
sortSelect.value = "popular";
localStorage.removeItem(storageKey);
updateResults();
}
searchInput.addEventListener("input", updateResults);
categorySelect.addEventListener("change", updateResults);
sortSelect.addEventListener("change", updateResults);
resetButton.addEventListener("click", resetFilters);
loadFilterState();
updateResults();
})();
<div class="vb-storage-five-demo">
<div class="vb-storage-five-directory" data-vb-storage-five>
<div class="vb-storage-five-head">
<span class="vb-storage-five-kicker">Example 05</span>
<h3>Saved Search Filters</h3>
<p>Search, filter, sort, refresh the page, and your selected directory filters will stay saved in localStorage.</p>
</div>
<div class="vb-storage-five-controls">
<label>
<span>Search resources</span>
<input type="search" data-search placeholder="Search JavaScript, WordPress, SEO...">
</label>
<label>
<span>Category</span>
<select data-category>
<option value="all">All categories</option>
<option value="JavaScript">JavaScript</option>
<option value="WordPress">WordPress</option>
<option value="SEO">SEO</option>
</select>
</label>
<label>
<span>Sort by</span>
<select data-sort>
<option value="popular">Most popular</option>
<option value="newest">Newest first</option>
<option value="az">Name A-Z</option>
</select>
</label>
<button type="button" data-reset-filters>Reset</button>
</div>
<div class="vb-storage-five-summary">
<strong data-result-count>0 results</strong>
<span data-filter-status>Filters are ready.</span>
</div>
<div class="vb-storage-five-results" data-results>
<article data-item data-title="JavaScript LocalStorage Guide" data-category="JavaScript" data-date="2026-06-01" data-popularity="98">
<span>JavaScript</span>
<h4>JavaScript LocalStorage Guide</h4>
<p>Save form data, carts, preferences, and UI state in the browser.</p>
</article>
<article data-item data-title="WordPress Custom Plugin Starter" data-category="WordPress" data-date="2026-05-12" data-popularity="91">
<span>WordPress</span>
<h4>WordPress Custom Plugin Starter</h4>
<p>Build lightweight WordPress plugins with custom frontend features.</p>
</article>
<article data-item data-title="Entity SEO Checklist" data-category="SEO" data-date="2026-05-30" data-popularity="96">
<span>SEO</span>
<h4>Entity SEO Checklist</h4>
<p>Improve structured data, internal links, and AI-readable content.</p>
</article>
<article data-item data-title="JavaScript Filter UI Examples" data-category="JavaScript" data-date="2026-04-20" data-popularity="89">
<span>JavaScript</span>
<h4>JavaScript Filter UI Examples</h4>
<p>Create searchable and filterable user interfaces with vanilla JavaScript.</p>
</article>
<article data-item data-title="WooCommerce Product UX Tips" data-category="WordPress" data-date="2026-03-18" data-popularity="86">
<span>WordPress</span>
<h4>WooCommerce Product UX Tips</h4>
<p>Improve product cards, checkout flows, quote forms, and mini carts.</p>
</article>
<article data-item data-title="Schema Markup for Blogs" data-category="SEO" data-date="2026-02-10" data-popularity="82">
<span>SEO</span>
<h4>Schema Markup for Blogs</h4>
<p>Add useful structured data to long-form SEO content and guides.</p>
</article>
</div>
</div>
</div>
.vb-storage-five-demo,
.vb-storage-five-demo * {
box-sizing: border-box;
}
.vb-storage-five-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 36px;
background:
radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
radial-gradient(circle at 84% 18%, rgba(236, 72, 153, 0.14), transparent 34%),
linear-gradient(135deg, #f8fafc 0%, #faf5ff 52%, #ffffff 100%) !important;
border: 1px solid rgba(168, 85, 247, 0.18);
box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}
.vb-storage-five-directory {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 30px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-five-head {
display: grid;
gap: 12px;
margin-bottom: 22px;
}
.vb-storage-five-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #f3e8ff;
color: #7e22ce !important;
-webkit-text-fill-color: #7e22ce !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-five-head h3 {
margin: 0 !important;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-five-head p {
max-width: 760px;
margin: 0 !important;
color: #4b5563 !important;
-webkit-text-fill-color: #4b5563 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-five-controls {
display: grid;
grid-template-columns: minmax(240px, 1fr) minmax(180px, 230px) minmax(180px, 230px) auto;
gap: 12px;
align-items: end;
padding: 16px;
border-radius: 24px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-five-controls label {
display: grid;
gap: 7px;
min-width: 0;
}
.vb-storage-five-controls label span {
color: #374151 !important;
-webkit-text-fill-color: #374151 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-five-controls input,
.vb-storage-five-controls select {
width: 100%;
min-height: 48px;
padding: 0 14px;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #ffffff;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 14px;
font-weight: 700;
outline: none;
}
.vb-storage-five-controls input:focus,
.vb-storage-five-controls select:focus {
border-color: rgba(147, 51, 234, 0.68);
box-shadow: 0 0 0 4px rgba(147, 51, 234, 0.10);
}
.vb-storage-five-controls button {
min-height: 48px;
padding: 0 16px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #7c3aed, #db2777);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-five-summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
margin: 18px 0;
padding: 13px 15px;
border-radius: 18px;
background: #faf5ff;
border: 1px solid rgba(168, 85, 247, 0.18);
}
.vb-storage-five-summary strong {
color: #7e22ce !important;
-webkit-text-fill-color: #7e22ce !important;
font-size: 15px;
font-weight: 950;
}
.vb-storage-five-summary span {
color: #6b21a8 !important;
-webkit-text-fill-color: #6b21a8 !important;
font-size: 13px;
font-weight: 750;
}
.vb-storage-five-results {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-five-results article {
display: grid;
align-content: start;
gap: 10px;
min-height: 210px;
padding: 18px;
border-radius: 24px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.24);
box-shadow: 0 15px 38px rgba(15, 23, 42, 0.07);
}
.vb-storage-five-results article.is-hidden {
display: none;
}
.vb-storage-five-results article span {
display: inline-flex;
justify-self: start;
padding: 7px 10px;
border-radius: 999px;
background: #f3e8ff;
color: #7e22ce !important;
-webkit-text-fill-color: #7e22ce !important;
font-size: 11px;
font-weight: 950;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.vb-storage-five-results article h4 {
margin: 0 !important;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 21px !important;
line-height: 1.15 !important;
font-weight: 950 !important;
}
.vb-storage-five-results article p {
margin: 0 !important;
color: #4b5563 !important;
-webkit-text-fill-color: #4b5563 !important;
font-size: 14px;
line-height: 1.6;
font-weight: 650;
}
@media (max-width: 980px) {
.vb-storage-five-controls {
grid-template-columns: 1fr 1fr;
}
.vb-storage-five-results {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.vb-storage-five-controls,
.vb-storage-five-results {
grid-template-columns: 1fr;
}
.vb-storage-five-controls button {
width: 100%;
}
.vb-storage-five-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This saved search filters localStorage example is useful for product archives, blog directories, resource libraries, job boards, real estate listings, course catalogs, SaaS dashboards, and searchable WordPress content sections.
A localStorage to-do list is one of the most searched JavaScript beginner projects, but it is also very useful for real UI features. The same logic can power saved checklists, task widgets, onboarding steps, dashboard notes, project lists, and progress trackers.
This example lets users add tasks, mark them complete, delete individual tasks, clear completed tasks, and keep the full task list saved after refresh. JavaScript stores the task array in localStorage and renders the list from saved browser data.
Add tasks and mark them complete. Your checklist is saved in localStorage and restored after page refresh.
No tasks yet. Add your first task.
(function () {
const wrapper = document.querySelector("[data-vb-storage-six]");
if (!wrapper) return;
const storageKey = "vbStorageSixTasks";
const form = wrapper.querySelector("[data-task-form]");
const input = wrapper.querySelector("[data-task-input]");
const taskList = wrapper.querySelector("[data-task-list]");
const clearCompletedButton = wrapper.querySelector("[data-clear-completed]");
const totalCount = wrapper.querySelector("[data-total-count]");
const doneCount = wrapper.querySelector("[data-done-count]");
let tasks = [];
function saveTasks() {
localStorage.setItem(storageKey, JSON.stringify(tasks));
}
function loadTasks() {
const savedTasks = localStorage.getItem(storageKey);
if (!savedTasks) return;
try {
const parsedTasks = JSON.parse(savedTasks);
tasks = Array.isArray(parsedTasks) ? parsedTasks : [];
} catch (error) {
tasks = [];
localStorage.removeItem(storageKey);
}
}
function updateStats() {
const completedTasks = tasks.filter(function (task) {
return task.completed;
});
totalCount.textContent = tasks.length;
doneCount.textContent = completedTasks.length;
}
function renderTasks() {
taskList.innerHTML = "";
if (tasks.length === 0) {
taskList.innerHTML = '<p class="vb-storage-six-empty">No tasks yet. Add your first task.</p>';
updateStats();
return;
}
tasks.forEach(function (task) {
const item = document.createElement("div");
item.className = "vb-storage-six-task";
item.classList.toggle("is-complete", task.completed);
item.innerHTML =
'<input type="checkbox" data-toggle-task="' + task.id + '"' + (task.completed ? " checked" : "") + '>' +
'<span>' + task.text + '</span>' +
'<button class="vb-storage-six-delete" type="button" data-delete-task="' + task.id + '">×</button>';
taskList.appendChild(item);
});
updateStats();
}
function addTask(text) {
tasks.unshift({
id: String(Date.now()),
text: text,
completed: false
});
saveTasks();
renderTasks();
}
function toggleTask(taskId) {
tasks = tasks.map(function (task) {
if (task.id === taskId) {
return {
id: task.id,
text: task.text,
completed: !task.completed
};
}
return task;
});
saveTasks();
renderTasks();
}
function deleteTask(taskId) {
tasks = tasks.filter(function (task) {
return task.id !== taskId;
});
saveTasks();
renderTasks();
}
form.addEventListener("submit", function (event) {
event.preventDefault();
const taskText = input.value.trim();
if (!taskText) return;
addTask(taskText);
input.value = "";
input.focus();
});
taskList.addEventListener("click", function (event) {
const toggleId = event.target.getAttribute("data-toggle-task");
const deleteId = event.target.getAttribute("data-delete-task");
if (toggleId) {
toggleTask(toggleId);
}
if (deleteId) {
deleteTask(deleteId);
}
});
clearCompletedButton.addEventListener("click", function () {
tasks = tasks.filter(function (task) {
return !task.completed;
});
saveTasks();
renderTasks();
});
loadTasks();
renderTasks();
})();
<div class="vb-storage-six-demo">
<div class="vb-storage-six-app" data-vb-storage-six>
<div class="vb-storage-six-left">
<span class="vb-storage-six-kicker">Example 06</span>
<h3>Saved To-Do List</h3>
<p>Add tasks and mark them complete. Your checklist is saved in localStorage and restored after page refresh.</p>
<form class="vb-storage-six-form" data-task-form>
<input type="text" data-task-input placeholder="Add a new task...">
<button type="submit">Add Task</button>
</form>
<div class="vb-storage-six-stats">
<div>
<span>Total</span>
<strong data-total-count>0</strong>
</div>
<div>
<span>Done</span>
<strong data-done-count>0</strong>
</div>
</div>
</div>
<div class="vb-storage-six-list-card">
<div class="vb-storage-six-list-head">
<strong>Project Checklist</strong>
<button type="button" data-clear-completed>Clear Completed</button>
</div>
<div class="vb-storage-six-list" data-task-list>
<p class="vb-storage-six-empty">No tasks yet. Add your first task.</p>
</div>
</div>
</div>
</div>
.vb-storage-six-demo,
.vb-storage-six-demo * {
box-sizing: border-box;
}
.vb-storage-six-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 18% 18%, rgba(245, 158, 11, 0.20), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(244, 63, 94, 0.16), transparent 34%),
linear-gradient(135deg, #fffbeb 0%, #fff1f2 55%, #ffffff 100%) !important;
border: 1px solid rgba(245, 158, 11, 0.22);
box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}
.vb-storage-six-app {
display: grid;
grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
gap: 22px;
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #111827;
box-shadow: 0 28px 90px rgba(17, 24, 39, 0.28);
}
.vb-storage-six-left,
.vb-storage-six-list-card {
min-width: 0;
}
.vb-storage-six-left {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background:
radial-gradient(circle at 18% 18%, rgba(251, 191, 36, 0.15), transparent 34%),
rgba(255,255,255,0.07);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-six-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(251, 191, 36, 0.14);
color: #fde68a !important;
-webkit-text-fill-color: #fde68a !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-six-left h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-six-left p {
max-width: 540px;
margin: 0 0 22px !important;
color: #d1d5db !important;
-webkit-text-fill-color: #d1d5db !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-six-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
margin-bottom: 18px;
}
.vb-storage-six-form input {
min-width: 0;
min-height: 50px;
padding: 0 15px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 999px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
font-weight: 750;
outline: none;
}
.vb-storage-six-form input::placeholder {
color: #9ca3af;
-webkit-text-fill-color: #9ca3af;
}
.vb-storage-six-form input:focus {
border-color: rgba(251, 191, 36, 0.70);
box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.12);
}
.vb-storage-six-form button,
.vb-storage-six-list-head button,
.vb-storage-six-delete {
border: 0;
cursor: pointer;
font-weight: 950;
}
.vb-storage-six-form button {
min-height: 50px;
padding: 0 16px;
border-radius: 999px;
background: linear-gradient(135deg, #f59e0b, #f43f5e);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
box-shadow: 0 16px 38px rgba(244, 63, 94, 0.28);
}
.vb-storage-six-stats {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.vb-storage-six-stats div {
padding: 16px;
border-radius: 22px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-six-stats span {
display: block;
margin-bottom: 7px;
color: #fed7aa !important;
-webkit-text-fill-color: #fed7aa !important;
font-size: 12px;
font-weight: 900;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.vb-storage-six-stats strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 32px;
line-height: 1;
font-weight: 950;
}
.vb-storage-six-list-card {
display: grid;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-six-list-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.vb-storage-six-list-head strong {
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-six-list-head button {
min-height: 40px;
padding: 9px 13px;
border-radius: 999px;
background: #fff7ed;
color: #c2410c !important;
-webkit-text-fill-color: #c2410c !important;
font-size: 12px;
}
.vb-storage-six-list {
display: grid;
gap: 10px;
min-height: 270px;
}
.vb-storage-six-empty {
display: grid;
place-items: center;
min-height: 270px;
margin: 0 !important;
border: 1px dashed rgba(148, 163, 184, 0.55);
border-radius: 22px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-six-task {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
padding: 13px;
border-radius: 18px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-six-task input {
width: 20px;
height: 20px;
accent-color: #f59e0b;
}
.vb-storage-six-task span {
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 15px;
line-height: 1.4;
font-weight: 750;
overflow-wrap: anywhere;
}
.vb-storage-six-task.is-complete span {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
text-decoration: line-through;
}
.vb-storage-six-delete {
width: 34px;
height: 34px;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 16px;
}
@media (max-width: 900px) {
.vb-storage-six-app {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-six-form {
grid-template-columns: 1fr;
}
.vb-storage-six-left h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-six-form button {
width: 100%;
}
}
This localStorage to-do list example is useful for JavaScript beginner projects, dashboard checklist widgets, onboarding task lists, project planning tools, saved notes, habit trackers, and lightweight browser-based productivity apps.
If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.
A favorite products feature is useful for ecommerce stores, affiliate product lists, directories, comparison pages, SaaS template galleries, and digital product shops. Visitors can save items they like and return to the page later without losing their selected favorites.
This example lets users favorite and unfavorite product cards. JavaScript saves the selected favorite product IDs in localStorage, updates the heart buttons instantly, shows a saved favorites panel, and restores the same state after refresh.
Click the heart buttons to save favorite products. Refresh the page and your selected products will still be marked.
Technical SEO, content structure, speed, and schema review.
149€Lightweight custom plugin built for your exact website workflow.
399€Modern responsive section with custom HTML, CSS, and JavaScript.
99€Mini cart, product filter, quote form, or saved product feature.
249€(function () {
const wrapper = document.querySelector("[data-vb-storage-seven]");
if (!wrapper) return;
const storageKey = "vbStorageSevenFavorites";
const productCards = Array.from(wrapper.querySelectorAll("[data-product-card]"));
const favoriteButtons = wrapper.querySelectorAll("[data-favorite-button]");
const favoriteList = wrapper.querySelector("[data-favorite-list]");
const favoriteCount = wrapper.querySelector("[data-favorite-count]");
const clearButton = wrapper.querySelector("[data-clear-favorites]");
let favoriteIds = [];
function saveFavorites() {
localStorage.setItem(storageKey, JSON.stringify(favoriteIds));
}
function loadFavorites() {
const savedFavorites = localStorage.getItem(storageKey);
if (!savedFavorites) return;
try {
const parsedFavorites = JSON.parse(savedFavorites);
favoriteIds = Array.isArray(parsedFavorites) ? parsedFavorites : [];
} catch (error) {
favoriteIds = [];
localStorage.removeItem(storageKey);
}
}
function getProductById(productId) {
return productCards.find(function (card) {
return card.getAttribute("data-id") === productId;
});
}
function renderFavorites() {
favoriteList.innerHTML = "";
productCards.forEach(function (card) {
const productId = card.getAttribute("data-id");
const isFavorite = favoriteIds.includes(productId);
const heart = card.querySelector("[data-favorite-button]");
card.classList.toggle("is-favorite", isFavorite);
heart.textContent = isFavorite ? "♥" : "♡";
});
favoriteCount.textContent = favoriteIds.length === 1 ? "1 saved" : favoriteIds.length + " saved";
if (favoriteIds.length === 0) {
favoriteList.innerHTML = '<p class="vb-storage-seven-empty">No favorites saved yet.</p>';
return;
}
favoriteIds.forEach(function (productId) {
const card = getProductById(productId);
if (!card) return;
const item = document.createElement("div");
item.className = "vb-storage-seven-favorite-item";
item.innerHTML =
'<span>♥</span>' +
'<strong>' + card.getAttribute("data-name") + '</strong>';
favoriteList.appendChild(item);
});
}
function toggleFavorite(productId) {
if (favoriteIds.includes(productId)) {
favoriteIds = favoriteIds.filter(function (id) {
return id !== productId;
});
} else {
favoriteIds.push(productId);
}
saveFavorites();
renderFavorites();
}
favoriteButtons.forEach(function (button) {
button.addEventListener("click", function () {
const card = button.closest("[data-product-card]");
toggleFavorite(card.getAttribute("data-id"));
});
});
clearButton.addEventListener("click", function () {
favoriteIds = [];
saveFavorites();
renderFavorites();
});
loadFavorites();
renderFavorites();
})();
<div class="vb-storage-seven-demo">
<div class="vb-storage-seven-wrap" data-vb-storage-seven>
<div class="vb-storage-seven-head">
<span class="vb-storage-seven-kicker">Example 07</span>
<h3>Saved Favorite Products</h3>
<p>Click the heart buttons to save favorite products. Refresh the page and your selected products will still be marked.</p>
</div>
<div class="vb-storage-seven-layout">
<div class="vb-storage-seven-products">
<article class="vb-storage-seven-card" data-product-card data-id="website-audit" data-name="Website SEO Audit">
<button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
<div class="vb-storage-seven-icon">SEO</div>
<h4>Website SEO Audit</h4>
<p>Technical SEO, content structure, speed, and schema review.</p>
<strong>149€</strong>
</article>
<article class="vb-storage-seven-card" data-product-card data-id="plugin-build" data-name="Custom WordPress Plugin">
<button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
<div class="vb-storage-seven-icon">WP</div>
<h4>Custom WordPress Plugin</h4>
<p>Lightweight custom plugin built for your exact website workflow.</p>
<strong>399€</strong>
</article>
<article class="vb-storage-seven-card" data-product-card data-id="landing-section" data-name="Landing Page Section">
<button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
<div class="vb-storage-seven-icon">UI</div>
<h4>Landing Page Section</h4>
<p>Modern responsive section with custom HTML, CSS, and JavaScript.</p>
<strong>99€</strong>
</article>
<article class="vb-storage-seven-card" data-product-card data-id="shop-feature" data-name="Ecommerce Feature">
<button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
<div class="vb-storage-seven-icon">EC</div>
<h4>Ecommerce Feature</h4>
<p>Mini cart, product filter, quote form, or saved product feature.</p>
<strong>249€</strong>
</article>
</div>
<aside class="vb-storage-seven-panel">
<div class="vb-storage-seven-panel-head">
<strong>Saved Favorites</strong>
<span data-favorite-count>0 saved</span>
</div>
<div class="vb-storage-seven-list" data-favorite-list>
<p class="vb-storage-seven-empty">No favorites saved yet.</p>
</div>
<button type="button" data-clear-favorites>Clear Favorites</button>
</aside>
</div>
</div>
</div>
.vb-storage-seven-demo,
.vb-storage-seven-demo * {
box-sizing: border-box;
}
.vb-storage-seven-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 46px;
background:
radial-gradient(circle at 12% 18%, rgba(244, 63, 94, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
linear-gradient(135deg, #fff1f2 0%, #faf5ff 54%, #ffffff 100%) !important;
border: 1px solid rgba(244, 63, 94, 0.18);
box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}
.vb-storage-seven-wrap {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-seven-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-seven-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #ffe4e6;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-seven-head h3 {
margin: 0 !important;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-seven-head p {
max-width: 760px;
margin: 0 !important;
color: #4b5563 !important;
-webkit-text-fill-color: #4b5563 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-seven-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
gap: 20px;
align-items: start;
}
.vb-storage-seven-products {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-seven-card {
position: relative;
display: grid;
align-content: start;
gap: 12px;
min-height: 270px;
padding: 18px;
border-radius: 26px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.24);
transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}
.vb-storage-seven-card.is-favorite {
border-color: rgba(244, 63, 94, 0.52);
background: linear-gradient(135deg, #fff1f2, #ffffff) !important;
box-shadow: 0 18px 46px rgba(244, 63, 94, 0.12);
}
.vb-storage-seven-card:hover {
transform: translateY(-3px);
}
.vb-storage-seven-heart {
position: absolute;
top: 16px;
right: 16px;
display: grid;
place-items: center;
width: 42px;
height: 42px;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 25px;
line-height: 1;
font-weight: 950;
cursor: pointer;
box-shadow: 0 12px 28px rgba(15, 23, 42, 0.10);
}
.vb-storage-seven-card.is-favorite .vb-storage-seven-heart {
background: #e11d48;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-seven-icon {
display: grid;
place-items: center;
width: 74px;
height: 74px;
border-radius: 24px;
background: linear-gradient(135deg, #e11d48, #9333ea);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 18px;
font-weight: 950;
}
.vb-storage-seven-card h4 {
margin: 0 !important;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 22px !important;
line-height: 1.12 !important;
font-weight: 950 !important;
}
.vb-storage-seven-card p {
margin: 0 !important;
color: #4b5563 !important;
-webkit-text-fill-color: #4b5563 !important;
font-size: 14px;
line-height: 1.6;
font-weight: 650;
}
.vb-storage-seven-card strong {
align-self: end;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 24px;
line-height: 1;
font-weight: 950;
}
.vb-storage-seven-panel {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #111827;
box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}
.vb-storage-seven-panel-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-seven-panel-head strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 22px;
font-weight: 950;
}
.vb-storage-seven-panel-head span {
color: #fecdd3 !important;
-webkit-text-fill-color: #fecdd3 !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-seven-list {
display: grid;
gap: 10px;
min-height: 250px;
}
.vb-storage-seven-empty {
display: grid;
place-items: center;
min-height: 250px;
margin: 0 !important;
border: 1px dashed rgba(255,255,255,0.22);
border-radius: 20px;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-seven-favorite-item {
display: grid;
grid-template-columns: 44px minmax(0, 1fr);
gap: 12px;
align-items: center;
padding: 12px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-seven-favorite-item span {
display: grid;
place-items: center;
width: 44px;
height: 44px;
border-radius: 15px;
background: linear-gradient(135deg, #e11d48, #9333ea);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 18px;
font-weight: 950;
}
.vb-storage-seven-favorite-item strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
line-height: 1.2;
font-weight: 900;
}
.vb-storage-seven-panel > button {
min-height: 44px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #e11d48, #9333ea);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
@media (max-width: 940px) {
.vb-storage-seven-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-seven-products {
grid-template-columns: 1fr;
}
.vb-storage-seven-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This favorite products localStorage example is useful for ecommerce stores, affiliate websites, product comparison pages, service package lists, saved template galleries, and WooCommerce-style product cards.
Saving multi-step form progress is very useful for quote forms, onboarding flows, checkout forms, application forms, booking forms, and lead generation pages. It prevents users from losing their progress when they refresh the page or come back later.
This example saves the active step and form values in localStorage. Visitors can move between steps, fill in fields, refresh the page, and continue from the same step with the same saved answers.
Fill out the steps, refresh the page, and your form progress will be restored from localStorage.
(function () {
const wrapper = document.querySelector("[data-vb-storage-eight]");
if (!wrapper) return;
const storageKey = "vbStorageEightMultiStepForm";
const steps = Array.from(wrapper.querySelectorAll("[data-step]"));
const form = wrapper.querySelector(".vb-storage-eight-form");
const fields = Array.from(form.querySelectorAll("input, select, textarea"));
const previousButton = wrapper.querySelector("[data-prev-step]");
const nextButton = wrapper.querySelector("[data-next-step]");
const resetButton = wrapper.querySelector("[data-reset-form]");
const stepLabel = wrapper.querySelector("[data-step-label]");
const progressLine = wrapper.querySelector("[data-progress-line]");
let currentStep = 0;
function getFormData() {
const data = {};
fields.forEach(function (field) {
data[field.name] = field.value;
});
return data;
}
function saveProgress() {
localStorage.setItem(storageKey, JSON.stringify({
currentStep: currentStep,
formData: getFormData()
}));
}
function loadProgress() {
const savedProgress = localStorage.getItem(storageKey);
if (!savedProgress) return;
try {
const progress = JSON.parse(savedProgress);
currentStep = Number(progress.currentStep) || 0;
if (progress.formData) {
fields.forEach(function (field) {
field.value = progress.formData[field.name] || "";
});
}
} catch (error) {
currentStep = 0;
localStorage.removeItem(storageKey);
}
}
function showStep(stepIndex) {
currentStep = Math.max(0, Math.min(stepIndex, steps.length - 1));
steps.forEach(function (step, index) {
step.classList.toggle("is-active", index === currentStep);
});
previousButton.disabled = currentStep === 0;
nextButton.textContent = currentStep === steps.length - 1 ? "Finish" : "Next";
stepLabel.textContent = "Step " + (currentStep + 1) + " of " + steps.length;
progressLine.style.width = ((currentStep + 1) / steps.length * 100) + "%";
saveProgress();
}
fields.forEach(function (field) {
field.addEventListener("input", saveProgress);
field.addEventListener("change", saveProgress);
});
previousButton.addEventListener("click", function () {
showStep(currentStep - 1);
});
nextButton.addEventListener("click", function () {
if (currentStep < steps.length - 1) {
showStep(currentStep + 1);
} else {
saveProgress();
stepLabel.textContent = "Progress saved in localStorage";
}
});
resetButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
form.reset();
currentStep = 0;
showStep(0);
});
loadProgress();
showStep(currentStep);
})();
<div class="vb-storage-eight-demo">
<div class="vb-storage-eight-formbox" data-vb-storage-eight>
<div class="vb-storage-eight-intro">
<span class="vb-storage-eight-kicker">Example 08</span>
<h3>Saved Multi-Step Form</h3>
<p>Fill out the steps, refresh the page, and your form progress will be restored from localStorage.</p>
</div>
<div class="vb-storage-eight-progress">
<span data-progress-line></span>
</div>
<form class="vb-storage-eight-form">
<section class="vb-storage-eight-step is-active" data-step="0">
<h4>Project Basics</h4>
<label>
<span>Project name</span>
<input type="text" name="projectName" placeholder="New website project">
</label>
<label>
<span>Project type</span>
<select name="projectType">
<option value="">Choose type</option>
<option value="Website">Website</option>
<option value="Ecommerce">Ecommerce</option>
<option value="WordPress Plugin">WordPress Plugin</option>
</select>
</label>
</section>
<section class="vb-storage-eight-step" data-step="1">
<h4>Budget and Timeline</h4>
<label>
<span>Estimated budget</span>
<select name="budget">
<option value="">Choose budget</option>
<option value="500-1000€">500-1000€</option>
<option value="1000-3000€">1000-3000€</option>
<option value="3000€+">3000€+</option>
</select>
</label>
<label>
<span>Timeline</span>
<input type="text" name="timeline" placeholder="Example: 2-4 weeks">
</label>
</section>
<section class="vb-storage-eight-step" data-step="2">
<h4>Final Notes</h4>
<label>
<span>What should be included?</span>
<textarea name="notes" rows="5" placeholder="Describe the features, pages, design style, or functionality..."></textarea>
</label>
</section>
<div class="vb-storage-eight-actions">
<button type="button" data-prev-step>Back</button>
<span data-step-label>Step 1 of 3</span>
<button type="button" data-next-step>Next</button>
</div>
<button class="vb-storage-eight-reset" type="button" data-reset-form>Reset Saved Progress</button>
</form>
</div>
</div>
.vb-storage-eight-demo,
.vb-storage-eight-demo * {
box-sizing: border-box;
}
.vb-storage-eight-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 42px;
background:
radial-gradient(circle at 12% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #f0fdfa 54%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-eight-formbox {
max-width: 920px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}
.vb-storage-eight-intro {
display: grid;
gap: 12px;
margin-bottom: 22px;
}
.vb-storage-eight-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-eight-intro h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 64px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-eight-intro p {
max-width: 720px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-eight-progress {
height: 12px;
overflow: hidden;
margin-bottom: 20px;
border-radius: 999px;
background: #e2e8f0;
}
.vb-storage-eight-progress span {
display: block;
width: 33.33%;
height: 100%;
border-radius: 999px;
background: linear-gradient(135deg, #2563eb, #14b8a6);
transition: width 0.25s ease;
}
.vb-storage-eight-form {
display: grid;
gap: 16px;
}
.vb-storage-eight-step {
display: none;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 26px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-eight-step.is-active {
display: grid;
}
.vb-storage-eight-step h4 {
margin: 0 0 4px !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 28px !important;
line-height: 1.15 !important;
font-weight: 950 !important;
}
.vb-storage-eight-step label {
display: grid;
gap: 7px;
}
.vb-storage-eight-step label span {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-eight-step input,
.vb-storage-eight-step select,
.vb-storage-eight-step textarea {
width: 100%;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #ffffff;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
font-weight: 650;
outline: none;
}
.vb-storage-eight-step input,
.vb-storage-eight-step select {
min-height: 50px;
padding: 0 14px;
}
.vb-storage-eight-step textarea {
resize: vertical;
padding: 13px 14px;
line-height: 1.55;
}
.vb-storage-eight-step input:focus,
.vb-storage-eight-step select:focus,
.vb-storage-eight-step textarea:focus {
border-color: rgba(37, 99, 235, 0.74);
box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}
.vb-storage-eight-actions {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
}
.vb-storage-eight-actions button,
.vb-storage-eight-reset {
border: 0;
cursor: pointer;
font-weight: 950;
}
.vb-storage-eight-actions button {
min-height: 46px;
padding: 0 16px;
border-radius: 999px;
background: #e0f2fe;
color: #0369a1 !important;
-webkit-text-fill-color: #0369a1 !important;
font-size: 13px;
}
.vb-storage-eight-actions button:last-child {
background: linear-gradient(135deg, #2563eb, #14b8a6);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-eight-actions span {
text-align: center;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-eight-reset {
justify-self: start;
min-height: 42px;
padding: 0 14px;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 12px;
}
@media (max-width: 560px) {
.vb-storage-eight-intro h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-eight-actions {
grid-template-columns: 1fr;
}
.vb-storage-eight-actions span {
order: -1;
}
.vb-storage-eight-actions button,
.vb-storage-eight-reset {
width: 100%;
}
}
This localStorage multi-step form example is useful for quote request forms, checkout forms, onboarding flows, booking forms, lead generation pages, application forms, and longer WordPress contact forms.
A dismissible banner saved with localStorage is useful for cookie notices, announcement bars, discount banners, onboarding messages, update notices, and promotional website messages. Once the visitor closes the banner, localStorage can remember that choice.
This example shows a floating announcement banner with close and reset controls. JavaScript stores the dismissed state in localStorage, hides the banner after closing, and keeps it hidden after refresh until the demo reset button is used.
Close the banner and refresh the page. localStorage remembers that this message was dismissed.
The announcement banner appears inside this demo browser until the visitor closes it.
(function () {
const wrapper = document.querySelector("[data-vb-storage-nine]");
if (!wrapper) return;
const storageKey = "vbStorageNineBannerDismissed";
const banner = wrapper.querySelector("[data-banner]");
const closeButton = wrapper.querySelector("[data-close-banner]");
const resetButton = wrapper.querySelector("[data-reset-banner]");
const status = wrapper.querySelector("[data-banner-status]");
function updateBanner() {
const isDismissed = localStorage.getItem(storageKey) === "true";
banner.classList.toggle("is-hidden", isDismissed);
status.textContent = isDismissed
? "Banner status: hidden by localStorage"
: "Banner status: visible";
}
closeButton.addEventListener("click", function () {
localStorage.setItem(storageKey, "true");
updateBanner();
});
resetButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
updateBanner();
});
updateBanner();
})();
<div class="vb-storage-nine-demo">
<div class="vb-storage-nine-stage" data-vb-storage-nine>
<div class="vb-storage-nine-page">
<span class="vb-storage-nine-kicker">Example 09</span>
<h3>Dismissible Saved Banner</h3>
<p>Close the banner and refresh the page. localStorage remembers that this message was dismissed.</p>
<div class="vb-storage-nine-browser">
<div class="vb-storage-nine-browser-top">
<span></span>
<span></span>
<span></span>
</div>
<div class="vb-storage-nine-hero">
<strong>Website Content Area</strong>
<p>The announcement banner appears inside this demo browser until the visitor closes it.</p>
</div>
<div class="vb-storage-nine-banner" data-banner>
<div>
<strong>New website feature available</strong>
<p>Use localStorage to remember dismissed banners, cookie notices, and promo messages.</p>
</div>
<button type="button" data-close-banner>Close</button>
</div>
</div>
<div class="vb-storage-nine-footer">
<span data-banner-status>Banner status: visible</span>
<button type="button" data-reset-banner>Show Banner Again</button>
</div>
</div>
</div>
</div>
.vb-storage-nine-demo,
.vb-storage-nine-demo * {
box-sizing: border-box;
}
.vb-storage-nine-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
linear-gradient(135deg, #f0f9ff 0%, #fffbeb 54%, #ffffff 100%) !important;
border: 1px solid rgba(14, 165, 233, 0.18);
box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}
.vb-storage-nine-stage {
max-width: 1080px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #0f172a;
box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}
.vb-storage-nine-page {
display: grid;
gap: 16px;
}
.vb-storage-nine-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(14, 165, 233, 0.16);
color: #bae6fd !important;
-webkit-text-fill-color: #bae6fd !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-nine-page h3 {
max-width: 760px;
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-nine-page > p {
max-width: 760px;
margin: 0 0 8px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-nine-browser {
position: relative;
min-height: 390px;
overflow: hidden;
border-radius: 28px;
background: linear-gradient(135deg, #f8fafc, #e0f2fe) !important;
border: 1px solid rgba(255,255,255,0.14);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.24);
}
.vb-storage-nine-browser-top {
display: flex;
gap: 8px;
padding: 16px;
background: #ffffff;
border-bottom: 1px solid rgba(148, 163, 184, 0.22);
}
.vb-storage-nine-browser-top span {
width: 12px;
height: 12px;
border-radius: 999px;
background: #f87171;
}
.vb-storage-nine-browser-top span:nth-child(2) {
background: #fbbf24;
}
.vb-storage-nine-browser-top span:nth-child(3) {
background: #34d399;
}
.vb-storage-nine-hero {
display: grid;
place-items: center;
align-content: center;
min-height: 300px;
padding: 30px;
text-align: center;
}
.vb-storage-nine-hero strong {
margin-bottom: 10px;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(28px, 5vw, 48px);
line-height: 1;
font-weight: 950;
letter-spacing: -0.055em;
}
.vb-storage-nine-hero p {
max-width: 480px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 15px;
line-height: 1.65;
font-weight: 650;
}
.vb-storage-nine-banner {
position: absolute;
left: 18px;
right: 18px;
bottom: 18px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
padding: 16px;
border-radius: 22px;
background: #0f172a;
border: 1px solid rgba(255,255,255,0.12);
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.28);
}
.vb-storage-nine-banner.is-hidden {
display: none;
}
.vb-storage-nine-banner strong {
display: block;
margin-bottom: 5px;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 17px;
line-height: 1.2;
font-weight: 950;
}
.vb-storage-nine-banner p {
margin: 0 !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 13px;
line-height: 1.45;
font-weight: 650;
}
.vb-storage-nine-banner button,
.vb-storage-nine-footer button {
border: 0;
border-radius: 999px;
cursor: pointer;
font-weight: 950;
white-space: nowrap;
}
.vb-storage-nine-banner button {
min-height: 42px;
padding: 10px 14px;
background: linear-gradient(135deg, #0ea5e9, #f59e0b);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
}
.vb-storage-nine-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
padding: 14px 16px;
border-radius: 20px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-nine-footer span {
color: #e2e8f0 !important;
-webkit-text-fill-color: #e2e8f0 !important;
font-size: 14px;
font-weight: 800;
}
.vb-storage-nine-footer button {
min-height: 40px;
padding: 9px 13px;
background: #ffffff;
color: #0369a1 !important;
-webkit-text-fill-color: #0369a1 !important;
font-size: 12px;
}
@media (max-width: 640px) {
.vb-storage-nine-page h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-nine-banner {
align-items: stretch;
flex-direction: column;
}
.vb-storage-nine-banner button,
.vb-storage-nine-footer button {
width: 100%;
}
}
This dismissible banner localStorage example is useful for cookie notices, announcement bars, promo banners, onboarding messages, discount bars, website update alerts, and custom WordPress notification sections.
A localStorage notes app is one of the most useful JavaScript projects because it teaches saving, editing, deleting, rendering, and restoring user-generated content. The same logic can be used for dashboard notes, admin reminders, customer notes, private browser notes, and lightweight project planning widgets.
This example lets users create notes, edit existing notes, delete notes, and keep all notes saved after refresh. JavaScript stores an array of note objects in localStorage and rebuilds the note cards when the page loads again.
Create notes, edit them, delete them, and refresh the page. Your notes stay saved in localStorage.
No notes saved yet.
(function () {
const wrapper = document.querySelector("[data-vb-storage-ten]");
if (!wrapper) return;
const storageKey = "vbStorageTenNotes";
const form = wrapper.querySelector("[data-note-form]");
const titleInput = wrapper.querySelector("[data-note-title]");
const textInput = wrapper.querySelector("[data-note-text]");
const submitButton = wrapper.querySelector("[data-submit-note]");
const cancelEditButton = wrapper.querySelector("[data-cancel-edit]");
const noteList = wrapper.querySelector("[data-note-list]");
const noteCount = wrapper.querySelector("[data-note-count]");
let notes = [];
let editingId = null;
function saveNotes() {
localStorage.setItem(storageKey, JSON.stringify(notes));
}
function loadNotes() {
const savedNotes = localStorage.getItem(storageKey);
if (!savedNotes) return;
try {
const parsedNotes = JSON.parse(savedNotes);
notes = Array.isArray(parsedNotes) ? parsedNotes : [];
} catch (error) {
notes = [];
localStorage.removeItem(storageKey);
}
}
function resetForm() {
editingId = null;
form.reset();
submitButton.textContent = "Add Note";
cancelEditButton.hidden = true;
}
function renderNotes() {
noteList.innerHTML = "";
noteCount.textContent = notes.length === 1 ? "1 note" : notes.length + " notes";
if (notes.length === 0) {
noteList.innerHTML = '<p class="vb-storage-ten-empty">No notes saved yet.</p>';
return;
}
notes.forEach(function (note) {
const card = document.createElement("article");
card.className = "vb-storage-ten-note";
card.innerHTML =
'<h4>' + note.title + '</h4>' +
'<p>' + note.text + '</p>' +
'<small>Saved: ' + note.createdAt + '</small>' +
'<div class="vb-storage-ten-note-actions">' +
'<button type="button" data-edit-note="' + note.id + '">Edit</button>' +
'<button type="button" data-delete-note="' + note.id + '">Delete</button>' +
'</div>';
noteList.appendChild(card);
});
}
function addOrUpdateNote() {
const title = titleInput.value.trim();
const text = textInput.value.trim();
if (!title || !text) return;
if (editingId) {
notes = notes.map(function (note) {
if (note.id === editingId) {
return {
id: note.id,
title: title,
text: text,
createdAt: note.createdAt
};
}
return note;
});
} else {
notes.unshift({
id: String(Date.now()),
title: title,
text: text,
createdAt: new Date().toLocaleDateString()
});
}
saveNotes();
renderNotes();
resetForm();
}
function startEditing(noteId) {
const note = notes.find(function (item) {
return item.id === noteId;
});
if (!note) return;
editingId = note.id;
titleInput.value = note.title;
textInput.value = note.text;
submitButton.textContent = "Update Note";
cancelEditButton.hidden = false;
titleInput.focus();
}
function deleteNote(noteId) {
notes = notes.filter(function (note) {
return note.id !== noteId;
});
if (editingId === noteId) {
resetForm();
}
saveNotes();
renderNotes();
}
form.addEventListener("submit", function (event) {
event.preventDefault();
addOrUpdateNote();
});
noteList.addEventListener("click", function (event) {
const editId = event.target.getAttribute("data-edit-note");
const deleteId = event.target.getAttribute("data-delete-note");
if (editId) startEditing(editId);
if (deleteId) deleteNote(deleteId);
});
cancelEditButton.addEventListener("click", resetForm);
loadNotes();
renderNotes();
})();
<div class="vb-storage-ten-demo">
<div class="vb-storage-ten-app" data-vb-storage-ten>
<div class="vb-storage-ten-left">
<span class="vb-storage-ten-kicker">Example 10</span>
<h3>Saved Notes App</h3>
<p>Create notes, edit them, delete them, and refresh the page. Your notes stay saved in localStorage.</p>
<form class="vb-storage-ten-form" data-note-form>
<input type="text" data-note-title placeholder="Note title">
<textarea data-note-text rows="5" placeholder="Write your note here..."></textarea>
<button type="submit" data-submit-note>Add Note</button>
</form>
<button type="button" class="vb-storage-ten-cancel" data-cancel-edit hidden>Cancel Edit</button>
</div>
<div class="vb-storage-ten-board">
<div class="vb-storage-ten-board-head">
<strong>Saved Notes</strong>
<span data-note-count>0 notes</span>
</div>
<div class="vb-storage-ten-list" data-note-list>
<p class="vb-storage-ten-empty">No notes saved yet.</p>
</div>
</div>
</div>
</div>
.vb-storage-ten-demo,
.vb-storage-ten-demo * {
box-sizing: border-box;
}
.vb-storage-ten-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.15), transparent 34%),
linear-gradient(135deg, #fefce8 0%, #eff6ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(234, 179, 8, 0.22);
box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}
.vb-storage-ten-app {
display: grid;
grid-template-columns: minmax(0, 0.84fr) minmax(0, 1.16fr);
gap: 22px;
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-ten-left,
.vb-storage-ten-board {
min-width: 0;
}
.vb-storage-ten-left {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #111827;
}
.vb-storage-ten-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(250, 204, 21, 0.16);
color: #fef08a !important;
-webkit-text-fill-color: #fef08a !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-ten-left h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-ten-left p {
max-width: 520px;
margin: 0 0 22px !important;
color: #d1d5db !important;
-webkit-text-fill-color: #d1d5db !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-ten-form {
display: grid;
gap: 12px;
}
.vb-storage-ten-form input,
.vb-storage-ten-form textarea {
width: 100%;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 18px;
background: rgba(255,255,255,0.09);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 15px;
font-weight: 700;
outline: none;
}
.vb-storage-ten-form input {
min-height: 50px;
padding: 0 15px;
}
.vb-storage-ten-form textarea {
resize: vertical;
padding: 14px 15px;
line-height: 1.55;
}
.vb-storage-ten-form input::placeholder,
.vb-storage-ten-form textarea::placeholder {
color: #9ca3af;
-webkit-text-fill-color: #9ca3af;
}
.vb-storage-ten-form input:focus,
.vb-storage-ten-form textarea:focus {
border-color: rgba(250, 204, 21, 0.72);
box-shadow: 0 0 0 4px rgba(250, 204, 21, 0.12);
}
.vb-storage-ten-form button,
.vb-storage-ten-cancel,
.vb-storage-ten-note-actions button {
border: 0;
cursor: pointer;
font-weight: 950;
}
.vb-storage-ten-form button {
min-height: 50px;
border-radius: 999px;
background: linear-gradient(135deg, #eab308, #2563eb);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}
.vb-storage-ten-cancel {
align-self: flex-start;
min-height: 40px;
margin-top: 10px;
padding: 0 13px;
border-radius: 999px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 12px;
}
.vb-storage-ten-board {
display: grid;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-ten-board-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-ten-board-head strong {
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-ten-board-head span {
color: #2563eb !important;
-webkit-text-fill-color: #2563eb !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-ten-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
min-height: 330px;
}
.vb-storage-ten-empty {
grid-column: 1 / -1;
display: grid;
place-items: center;
min-height: 330px;
margin: 0 !important;
border: 1px dashed rgba(148, 163, 184, 0.55);
border-radius: 22px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-ten-note {
display: grid;
align-content: start;
gap: 10px;
min-height: 190px;
padding: 16px;
border-radius: 22px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.07);
}
.vb-storage-ten-note h4 {
margin: 0 !important;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 19px !important;
line-height: 1.18 !important;
font-weight: 950 !important;
}
.vb-storage-ten-note p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
overflow-wrap: anywhere;
}
.vb-storage-ten-note small {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 750;
}
.vb-storage-ten-note-actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-top: auto;
}
.vb-storage-ten-note-actions button {
min-height: 34px;
padding: 7px 11px;
border-radius: 999px;
font-size: 12px;
}
.vb-storage-ten-note-actions button:first-child {
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
}
.vb-storage-ten-note-actions button:last-child {
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
@media (max-width: 920px) {
.vb-storage-ten-app {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-ten-list {
grid-template-columns: 1fr;
}
.vb-storage-ten-left h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This localStorage notes app example is useful for JavaScript notes projects, dashboard widgets, admin reminders, customer notes, browser-based writing tools, and lightweight project planning interfaces.
Saving the active tab with localStorage is useful for dashboards, pricing sections, product details, account settings, documentation pages, profile areas, and long content sections. It lets the interface reopen the same tab after refresh instead of always starting from the first tab.
This example has three content tabs. JavaScript saves the selected tab key in localStorage, updates the active tab instantly, and restores the same tab when the page loads again.
Choose a tab and refresh the page. localStorage restores the same active tab automatically.
This panel could contain product details, account information, dashboard stats, or documentation summary content.
This panel can show feature lists, pricing details, comparison content, or product specifications.
This panel is useful for user preferences, dashboard controls, display options, and saved interface settings.
(function () {
const wrapper = document.querySelector("[data-vb-storage-eleven]");
if (!wrapper) return;
const storageKey = "vbStorageElevenActiveTab";
const buttons = wrapper.querySelectorAll("[data-tab-button]");
const panels = wrapper.querySelectorAll("[data-tab-panel]");
const currentTab = wrapper.querySelector("[data-current-tab]");
function activateTab(tabKey) {
buttons.forEach(function (button) {
button.classList.toggle("is-active", button.getAttribute("data-tab-button") === tabKey);
});
panels.forEach(function (panel) {
panel.classList.toggle("is-active", panel.getAttribute("data-tab-panel") === tabKey);
});
currentTab.textContent = tabKey;
localStorage.setItem(storageKey, tabKey);
}
buttons.forEach(function (button) {
button.addEventListener("click", function () {
activateTab(button.getAttribute("data-tab-button"));
});
});
const savedTab = localStorage.getItem(storageKey) || "overview";
activateTab(savedTab);
})();
<div class="vb-storage-eleven-demo">
<div class="vb-storage-eleven-tabs" data-vb-storage-eleven>
<div class="vb-storage-eleven-header">
<span class="vb-storage-eleven-kicker">Example 11</span>
<h3>Saved Active Tab</h3>
<p>Choose a tab and refresh the page. localStorage restores the same active tab automatically.</p>
</div>
<div class="vb-storage-eleven-shell">
<div class="vb-storage-eleven-nav" role="tablist">
<button type="button" data-tab-button="overview" class="is-active">Overview</button>
<button type="button" data-tab-button="features">Features</button>
<button type="button" data-tab-button="settings">Settings</button>
</div>
<div class="vb-storage-eleven-content">
<section data-tab-panel="overview" class="is-active">
<span>01</span>
<h4>Overview Tab</h4>
<p>This panel could contain product details, account information, dashboard stats, or documentation summary content.</p>
<ul>
<li>Good for default content</li>
<li>Restores after refresh</li>
<li>Stores only the selected tab key</li>
</ul>
</section>
<section data-tab-panel="features">
<span>02</span>
<h4>Features Tab</h4>
<p>This panel can show feature lists, pricing details, comparison content, or product specifications.</p>
<ul>
<li>Great for product pages</li>
<li>Useful for SaaS sections</li>
<li>Simple localStorage state</li>
</ul>
</section>
<section data-tab-panel="settings">
<span>03</span>
<h4>Settings Tab</h4>
<p>This panel is useful for user preferences, dashboard controls, display options, and saved interface settings.</p>
<ul>
<li>Useful for dashboards</li>
<li>Works after page reload</li>
<li>Easy to customize</li>
</ul>
</section>
</div>
<div class="vb-storage-eleven-status">
Current saved tab: <strong data-current-tab>overview</strong>
</div>
</div>
</div>
</div>
.vb-storage-eleven-demo,
.vb-storage-eleven-demo * {
box-sizing: border-box;
}
.vb-storage-eleven-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 34px;
background:
radial-gradient(circle at 14% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
linear-gradient(135deg, #f0fdfa 0%, #eef2ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(20, 184, 166, 0.18);
box-shadow: 0 28px 80px rgba(15, 118, 110, 0.10);
}
.vb-storage-eleven-tabs {
max-width: 1060px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 30px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-eleven-header {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-eleven-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #ccfbf1;
color: #0f766e !important;
-webkit-text-fill-color: #0f766e !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-eleven-header h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-eleven-header p {
max-width: 760px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-eleven-shell {
display: grid;
gap: 16px;
padding: 18px;
border-radius: 28px;
background: #0f172a;
}
.vb-storage-eleven-nav {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.vb-storage-eleven-nav button {
min-height: 44px;
padding: 10px 15px;
border: 0;
border-radius: 999px;
background: rgba(255,255,255,0.09);
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-eleven-nav button.is-active {
background: linear-gradient(135deg, #14b8a6, #6366f1);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
box-shadow: 0 16px 34px rgba(20, 184, 166, 0.22);
}
.vb-storage-eleven-content {
min-height: 330px;
}
.vb-storage-eleven-content section {
display: none;
min-height: 330px;
padding: clamp(20px, 4vw, 34px);
border-radius: 24px;
background:
radial-gradient(circle at 85% 15%, rgba(20, 184, 166, 0.16), transparent 34%),
linear-gradient(135deg, #ffffff, #f8fafc) !important;
}
.vb-storage-eleven-content section.is-active {
display: grid;
align-content: center;
gap: 14px;
}
.vb-storage-eleven-content section span {
display: inline-grid;
place-items: center;
width: 58px;
height: 58px;
border-radius: 18px;
background: linear-gradient(135deg, #14b8a6, #6366f1);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 18px;
font-weight: 950;
}
.vb-storage-eleven-content section h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(28px, 4vw, 44px) !important;
line-height: 1.05 !important;
font-weight: 950 !important;
letter-spacing: -0.055em;
}
.vb-storage-eleven-content section p {
max-width: 680px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-eleven-content section ul {
display: grid;
gap: 8px;
margin: 4px 0 0 !important;
padding-left: 20px !important;
}
.vb-storage-eleven-content section li {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-eleven-status {
padding: 13px 15px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 800;
}
.vb-storage-eleven-status strong {
color: #a7f3d0 !important;
-webkit-text-fill-color: #a7f3d0 !important;
}
@media (max-width: 640px) {
.vb-storage-eleven-header h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-eleven-nav {
flex-direction: column;
}
.vb-storage-eleven-nav button {
width: 100%;
}
}
This active tab localStorage example is useful for product detail tabs, pricing tabs, account settings, dashboard panels, documentation pages, FAQ categories, and custom WordPress content sections.
A product comparison list saved with localStorage is useful for ecommerce stores, affiliate product roundups, SaaS pricing pages, hosting comparison sites, software directories, and product review websites. It lets visitors add items to a comparison table and keep that selection after refresh.
This example lets users add and remove products from a comparison table. JavaScript stores selected product IDs in localStorage, updates the table instantly, prevents duplicate items, and restores the comparison list after page reload.
Add products to the comparison table. Refresh the page and the selected products stay saved in localStorage.
Good for small sites and simple landing pages.
19€Better for company websites and growing traffic.
49€Best for ecommerce, automation, and advanced features.
99€No products selected for comparison.
(function () {
const wrapper = document.querySelector("[data-vb-storage-twelve]");
if (!wrapper) return;
const storageKey = "vbStorageTwelveCompare";
const products = Array.from(wrapper.querySelectorAll("[data-product]"));
const compareTable = wrapper.querySelector("[data-compare-table]");
const compareCount = wrapper.querySelector("[data-compare-count]");
const clearButton = wrapper.querySelector("[data-clear-compare]");
let selectedIds = [];
function saveCompare() {
localStorage.setItem(storageKey, JSON.stringify(selectedIds));
}
function loadCompare() {
const savedCompare = localStorage.getItem(storageKey);
if (!savedCompare) return;
try {
const parsedCompare = JSON.parse(savedCompare);
selectedIds = Array.isArray(parsedCompare) ? parsedCompare : [];
} catch (error) {
selectedIds = [];
localStorage.removeItem(storageKey);
}
}
function getProductData(product) {
return {
id: product.getAttribute("data-id"),
name: product.getAttribute("data-name"),
price: product.getAttribute("data-price"),
speed: product.getAttribute("data-speed"),
support: product.getAttribute("data-support")
};
}
function renderCompare() {
products.forEach(function (product) {
const productId = product.getAttribute("data-id");
const isSelected = selectedIds.includes(productId);
product.classList.toggle("is-selected", isSelected);
product.querySelector("[data-add-compare]").textContent = isSelected ? "Added" : "Add to Compare";
});
compareCount.textContent = selectedIds.length === 1 ? "1 selected" : selectedIds.length + " selected";
if (selectedIds.length === 0) {
compareTable.innerHTML = '<p class="vb-storage-twelve-empty">No products selected for comparison.</p>';
return;
}
const selectedProducts = selectedIds
.map(function (id) {
return products.find(function (product) {
return product.getAttribute("data-id") === id;
});
})
.filter(Boolean)
.map(getProductData);
let tableHtml =
'<table>' +
'<thead>' +
'<tr>' +
'<th>Product</th>' +
'<th>Price</th>' +
'<th>Speed</th>' +
'<th>Support</th>' +
'<th></th>' +
'</tr>' +
'</thead>' +
'<tbody>';
selectedProducts.forEach(function (product) {
tableHtml +=
'<tr>' +
'<td>' + product.name + '</td>' +
'<td>' + product.price + '</td>' +
'<td>' + product.speed + '</td>' +
'<td>' + product.support + '</td>' +
'<td><button type="button" data-remove-compare="' + product.id + '">×</button></td>' +
'</tr>';
});
tableHtml += '</tbody></table>';
compareTable.innerHTML = tableHtml;
}
function toggleCompare(productId) {
if (selectedIds.includes(productId)) {
selectedIds = selectedIds.filter(function (id) {
return id !== productId;
});
} else {
selectedIds.push(productId);
}
saveCompare();
renderCompare();
}
products.forEach(function (product) {
product.querySelector("[data-add-compare]").addEventListener("click", function () {
toggleCompare(product.getAttribute("data-id"));
});
});
compareTable.addEventListener("click", function (event) {
const removeId = event.target.getAttribute("data-remove-compare");
if (!removeId) return;
selectedIds = selectedIds.filter(function (id) {
return id !== removeId;
});
saveCompare();
renderCompare();
});
clearButton.addEventListener("click", function () {
selectedIds = [];
saveCompare();
renderCompare();
});
loadCompare();
renderCompare();
})();
<div class="vb-storage-twelve-demo">
<div class="vb-storage-twelve-compare" data-vb-storage-twelve>
<div class="vb-storage-twelve-head">
<span class="vb-storage-twelve-kicker">Example 12</span>
<h3>Saved Product Compare</h3>
<p>Add products to the comparison table. Refresh the page and the selected products stay saved in localStorage.</p>
</div>
<div class="vb-storage-twelve-grid">
<div class="vb-storage-twelve-products">
<article data-product data-id="starter" data-name="Starter Plan" data-price="19€" data-speed="Fast" data-support="Email">
<span>Starter</span>
<h4>Starter Plan</h4>
<p>Good for small sites and simple landing pages.</p>
<strong>19€</strong>
<button type="button" data-add-compare>Add to Compare</button>
</article>
<article data-product data-id="business" data-name="Business Plan" data-price="49€" data-speed="Very Fast" data-support="Priority">
<span>Business</span>
<h4>Business Plan</h4>
<p>Better for company websites and growing traffic.</p>
<strong>49€</strong>
<button type="button" data-add-compare>Add to Compare</button>
</article>
<article data-product data-id="pro" data-name="Pro Plan" data-price="99€" data-speed="Ultra Fast" data-support="Premium">
<span>Pro</span>
<h4>Pro Plan</h4>
<p>Best for ecommerce, automation, and advanced features.</p>
<strong>99€</strong>
<button type="button" data-add-compare>Add to Compare</button>
</article>
</div>
<div class="vb-storage-twelve-tablebox">
<div class="vb-storage-twelve-table-head">
<strong>Compare Products</strong>
<span data-compare-count>0 selected</span>
</div>
<div class="vb-storage-twelve-table" data-compare-table>
<p class="vb-storage-twelve-empty">No products selected for comparison.</p>
</div>
<button type="button" class="vb-storage-twelve-clear" data-clear-compare>Clear Compare</button>
</div>
</div>
</div>
</div>
.vb-storage-twelve-demo,
.vb-storage-twelve-demo * {
box-sizing: border-box;
}
.vb-storage-twelve-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.14), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #fdf2f8 55%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-twelve-compare {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twelve-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-twelve-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twelve-head h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twelve-head p {
max-width: 780px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twelve-grid {
display: grid;
grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
gap: 20px;
align-items: start;
}
.vb-storage-twelve-products {
display: grid;
gap: 14px;
}
.vb-storage-twelve-products article {
display: grid;
gap: 9px;
padding: 18px;
border-radius: 24px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.22);
}
.vb-storage-twelve-products article.is-selected {
border-color: rgba(37, 99, 235, 0.54);
box-shadow: 0 16px 40px rgba(37, 99, 235, 0.10);
}
.vb-storage-twelve-products article span {
display: inline-flex;
justify-self: start;
padding: 7px 10px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 11px;
font-weight: 950;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.vb-storage-twelve-products article h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 23px !important;
line-height: 1.12 !important;
font-weight: 950 !important;
}
.vb-storage-twelve-products article p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
}
.vb-storage-twelve-products article strong {
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 26px;
font-weight: 950;
}
.vb-storage-twelve-products article button,
.vb-storage-twelve-clear {
min-height: 42px;
border: 0;
border-radius: 999px;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twelve-products article button {
justify-self: start;
padding: 0 14px;
background: linear-gradient(135deg, #2563eb, #db2777);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-twelve-products article.is-selected button {
background: #e0e7ff;
color: #3730a3 !important;
-webkit-text-fill-color: #3730a3 !important;
}
.vb-storage-twelve-tablebox {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #111827;
box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}
.vb-storage-twelve-table-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.vb-storage-twelve-table-head strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 22px;
font-weight: 950;
}
.vb-storage-twelve-table-head span {
color: #bfdbfe !important;
-webkit-text-fill-color: #bfdbfe !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-twelve-table {
min-height: 270px;
overflow-x: auto;
}
.vb-storage-twelve-empty {
display: grid;
place-items: center;
min-height: 270px;
margin: 0 !important;
border: 1px dashed rgba(255,255,255,0.22);
border-radius: 20px;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-twelve-table table {
width: 100%;
min-width: 520px;
border-collapse: separate;
border-spacing: 0 9px;
}
.vb-storage-twelve-table th {
padding: 10px;
color: #bfdbfe !important;
-webkit-text-fill-color: #bfdbfe !important;
font-size: 12px;
text-align: left;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-twelve-table td {
padding: 12px 10px;
background: rgba(255,255,255,0.08);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 800;
}
.vb-storage-twelve-table td:first-child {
border-radius: 14px 0 0 14px;
}
.vb-storage-twelve-table td:last-child {
border-radius: 0 14px 14px 0;
}
.vb-storage-twelve-table td button {
width: 30px;
height: 30px;
border: 0;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 16px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twelve-clear {
background: #ffffff;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
}
@media (max-width: 960px) {
.vb-storage-twelve-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-twelve-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This product comparison localStorage example is useful for ecommerce product tables, affiliate comparison posts, hosting comparison pages, SaaS pricing tables, software directories, product review websites, and WooCommerce-style catalog features.
If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.
Saving quiz progress with localStorage is useful for online quizzes, course lessons, onboarding tests, product recommendation quizzes, lead generation quizzes, and learning platforms. It helps users continue from the same question after refreshing or returning later.
This example saves the current quiz question, selected answers, and score state in localStorage. Visitors can answer questions, move forward, refresh the page, and continue from the saved quiz progress.
Answer the quiz, refresh the page, and localStorage restores your current question and selected answers.
Your result will appear here.
(function () {
const wrapper = document.querySelector("[data-vb-storage-thirteen]");
if (!wrapper) return;
const storageKey = "vbStorageThirteenQuiz";
const questionCount = wrapper.querySelector("[data-question-count]");
const scoreLabel = wrapper.querySelector("[data-score-label]");
const progressBar = wrapper.querySelector("[data-progress-bar]");
const questionTitle = wrapper.querySelector("[data-question-title]");
const optionsBox = wrapper.querySelector("[data-options]");
const prevButton = wrapper.querySelector("[data-prev-question]");
const nextButton = wrapper.querySelector("[data-next-question]");
const resultBox = wrapper.querySelector("[data-result-box]");
const resultTitle = wrapper.querySelector("[data-result-title]");
const resultText = wrapper.querySelector("[data-result-text]");
const resetButton = wrapper.querySelector("[data-reset-quiz]");
const questions = [
{
title: "What does localStorage store values as?",
options: ["Numbers only", "Strings", "CSS variables"],
correct: "Strings"
},
{
title: "Which method saves a value in localStorage?",
options: ["localStorage.setItem()", "localStorage.push()", "localStorage.save()"],
correct: "localStorage.setItem()"
},
{
title: "What is commonly used to store arrays or objects?",
options: ["JSON.stringify()", "document.write()", "parseInt()"],
correct: "JSON.stringify()"
}
];
let state = {
currentQuestion: 0,
answers: {}
};
function saveState() {
localStorage.setItem(storageKey, JSON.stringify(state));
}
function loadState() {
const savedState = localStorage.getItem(storageKey);
if (!savedState) return;
try {
const parsedState = JSON.parse(savedState);
state.currentQuestion = Number(parsedState.currentQuestion) || 0;
state.answers = parsedState.answers || {};
} catch (error) {
localStorage.removeItem(storageKey);
}
}
function getScore() {
return questions.reduce(function (score, question, index) {
return state.answers[index] === question.correct ? score + 1 : score;
}, 0);
}
function renderQuiz() {
const question = questions[state.currentQuestion];
const selectedAnswer = state.answers[state.currentQuestion];
questionCount.textContent = "Question " + (state.currentQuestion + 1) + " of " + questions.length;
scoreLabel.textContent = "Score: " + getScore();
progressBar.style.width = ((state.currentQuestion + 1) / questions.length * 100) + "%";
questionTitle.textContent = question.title;
optionsBox.innerHTML = "";
question.options.forEach(function (option) {
const label = document.createElement("label");
label.className = "vb-storage-thirteen-option";
label.classList.toggle("is-selected", selectedAnswer === option);
label.innerHTML =
'<input type="radio" name="quizAnswer" value="' + option + '"' + (selectedAnswer === option ? " checked" : "") + '>' +
'<span>' + option + '</span>';
optionsBox.appendChild(label);
});
prevButton.disabled = state.currentQuestion === 0;
nextButton.textContent = state.currentQuestion === questions.length - 1 ? "Finish Quiz" : "Next";
resultBox.hidden = true;
saveState();
}
optionsBox.addEventListener("change", function (event) {
if (event.target.name !== "quizAnswer") return;
state.answers[state.currentQuestion] = event.target.value;
saveState();
renderQuiz();
});
prevButton.addEventListener("click", function () {
state.currentQuestion = Math.max(0, state.currentQuestion - 1);
renderQuiz();
});
nextButton.addEventListener("click", function () {
if (state.currentQuestion < questions.length - 1) {
state.currentQuestion += 1;
renderQuiz();
return;
}
const score = getScore();
resultBox.hidden = false;
resultTitle.textContent = "Quiz complete";
resultText.textContent = "You scored " + score + " out of " + questions.length + ". Your progress is still saved in localStorage.";
});
resetButton.addEventListener("click", function () {
state = {
currentQuestion: 0,
answers: {}
};
localStorage.removeItem(storageKey);
renderQuiz();
});
loadState();
renderQuiz();
})();
<div class="vb-storage-thirteen-demo">
<div class="vb-storage-thirteen-quiz" data-vb-storage-thirteen>
<div class="vb-storage-thirteen-intro">
<span class="vb-storage-thirteen-kicker">Example 13</span>
<h3>Saved Quiz Progress</h3>
<p>Answer the quiz, refresh the page, and localStorage restores your current question and selected answers.</p>
</div>
<div class="vb-storage-thirteen-card">
<div class="vb-storage-thirteen-top">
<span data-question-count>Question 1 of 3</span>
<strong data-score-label>Score: 0</strong>
</div>
<div class="vb-storage-thirteen-progress">
<span data-progress-bar></span>
</div>
<div class="vb-storage-thirteen-question">
<h4 data-question-title>Loading question...</h4>
<div class="vb-storage-thirteen-options" data-options></div>
</div>
<div class="vb-storage-thirteen-actions">
<button type="button" data-prev-question>Back</button>
<button type="button" data-next-question>Next</button>
</div>
<div class="vb-storage-thirteen-result" data-result-box hidden>
<strong data-result-title>Quiz complete</strong>
<p data-result-text>Your result will appear here.</p>
</div>
<button type="button" class="vb-storage-thirteen-reset" data-reset-quiz>Reset Saved Quiz</button>
</div>
</div>
</div>
.vb-storage-thirteen-demo,
.vb-storage-thirteen-demo * {
box-sizing: border-box;
}
.vb-storage-thirteen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
radial-gradient(circle at 86% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
linear-gradient(135deg, #eef2ff 0%, #ecfdf5 54%, #ffffff 100%) !important;
border: 1px solid rgba(99, 102, 241, 0.18);
box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}
.vb-storage-thirteen-quiz {
display: grid;
grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #111827;
box-shadow: 0 28px 90px rgba(17, 24, 39, 0.28);
}
.vb-storage-thirteen-intro {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 0;
padding: clamp(18px, 3vw, 26px);
}
.vb-storage-thirteen-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(99, 102, 241, 0.20);
color: #c7d2fe !important;
-webkit-text-fill-color: #c7d2fe !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-thirteen-intro h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-thirteen-intro p {
max-width: 540px;
margin: 0 !important;
color: #d1d5db !important;
-webkit-text-fill-color: #d1d5db !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-thirteen-card {
display: grid;
gap: 16px;
min-width: 0;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
}
.vb-storage-thirteen-top,
.vb-storage-thirteen-actions {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-thirteen-top span,
.vb-storage-thirteen-top strong {
font-size: 13px;
font-weight: 950;
}
.vb-storage-thirteen-top span {
color: #4f46e5 !important;
-webkit-text-fill-color: #4f46e5 !important;
}
.vb-storage-thirteen-top strong {
color: #059669 !important;
-webkit-text-fill-color: #059669 !important;
}
.vb-storage-thirteen-progress {
height: 12px;
overflow: hidden;
border-radius: 999px;
background: #e5e7eb;
}
.vb-storage-thirteen-progress span {
display: block;
width: 33.33%;
height: 100%;
border-radius: 999px;
background: linear-gradient(135deg, #6366f1, #10b981);
transition: width 0.25s ease;
}
.vb-storage-thirteen-question {
display: grid;
gap: 16px;
min-height: 270px;
padding: clamp(18px, 3vw, 24px);
border-radius: 24px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-thirteen-question h4 {
margin: 0 !important;
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: clamp(24px, 3vw, 34px) !important;
line-height: 1.12 !important;
font-weight: 950 !important;
letter-spacing: -0.04em;
}
.vb-storage-thirteen-options {
display: grid;
gap: 10px;
}
.vb-storage-thirteen-option {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 10px;
align-items: center;
padding: 13px 14px;
border: 1px solid rgba(148, 163, 184, 0.24);
border-radius: 16px;
background: #ffffff;
cursor: pointer;
}
.vb-storage-thirteen-option.is-selected {
border-color: rgba(99, 102, 241, 0.70);
background: #eef2ff;
}
.vb-storage-thirteen-option input {
width: 18px;
height: 18px;
accent-color: #6366f1;
}
.vb-storage-thirteen-option span {
color: #1f2937 !important;
-webkit-text-fill-color: #1f2937 !important;
font-size: 15px;
line-height: 1.35;
font-weight: 750;
}
.vb-storage-thirteen-actions button,
.vb-storage-thirteen-reset {
min-height: 44px;
border: 0;
border-radius: 999px;
cursor: pointer;
font-size: 13px;
font-weight: 950;
}
.vb-storage-thirteen-actions button {
padding: 0 16px;
background: #e0e7ff;
color: #3730a3 !important;
-webkit-text-fill-color: #3730a3 !important;
}
.vb-storage-thirteen-actions button:last-child {
background: linear-gradient(135deg, #6366f1, #10b981);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-thirteen-actions button:disabled {
opacity: 0.52;
cursor: not-allowed;
}
.vb-storage-thirteen-result {
padding: 16px;
border-radius: 20px;
background: #ecfdf5;
border: 1px solid rgba(16, 185, 129, 0.24);
}
.vb-storage-thirteen-result strong {
display: block;
margin-bottom: 6px;
color: #047857 !important;
-webkit-text-fill-color: #047857 !important;
font-size: 18px;
font-weight: 950;
}
.vb-storage-thirteen-result p {
margin: 0 !important;
color: #065f46 !important;
-webkit-text-fill-color: #065f46 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 750;
}
.vb-storage-thirteen-reset {
justify-self: start;
padding: 0 14px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
@media (max-width: 920px) {
.vb-storage-thirteen-quiz {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-thirteen-intro h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-thirteen-actions {
flex-direction: column;
}
.vb-storage-thirteen-actions button,
.vb-storage-thirteen-reset {
width: 100%;
}
}
This quiz progress localStorage example is useful for JavaScript quiz apps, online course lessons, onboarding questionnaires, product recommendation quizzes, lead generation quizzes, learning platforms, and interactive website assessments.
Saving calculator history with localStorage is useful for price calculators, loan calculators, quote calculators, discount calculators, BMI calculators, tax calculators, and form-based tools. It helps users compare previous results without needing a backend database.
This example calculates a simple project price estimate from hours and hourly rate. JavaScript saves each calculated result into localStorage, displays a history list, and restores previous calculations after page refresh.
Calculate a project estimate and save every result in localStorage for later comparison.
No saved calculations yet.
(function () {
const wrapper = document.querySelector("[data-vb-storage-fourteen]");
if (!wrapper) return;
const storageKey = "vbStorageFourteenCalculatorHistory";
const form = wrapper.querySelector("[data-calc-form]");
const projectInput = wrapper.querySelector("[data-project-name]");
const hoursInput = wrapper.querySelector("[data-hours]");
const rateInput = wrapper.querySelector("[data-rate]");
const currentTotal = wrapper.querySelector("[data-current-total]");
const historyList = wrapper.querySelector("[data-history-list]");
const clearButton = wrapper.querySelector("[data-clear-history]");
let history = [];
function saveHistory() {
localStorage.setItem(storageKey, JSON.stringify(history));
}
function loadHistory() {
const savedHistory = localStorage.getItem(storageKey);
if (!savedHistory) return;
try {
const parsedHistory = JSON.parse(savedHistory);
history = Array.isArray(parsedHistory) ? parsedHistory : [];
} catch (error) {
history = [];
localStorage.removeItem(storageKey);
}
}
function calculateTotal() {
const hours = Number(hoursInput.value) || 0;
const rate = Number(rateInput.value) || 0;
return hours * rate;
}
function updateCurrentTotal() {
currentTotal.textContent = calculateTotal() + "€";
}
function renderHistory() {
historyList.innerHTML = "";
if (history.length === 0) {
historyList.innerHTML = '<p class="vb-storage-fourteen-empty">No saved calculations yet.</p>';
return;
}
history.forEach(function (item) {
const historyItem = document.createElement("div");
historyItem.className = "vb-storage-fourteen-item";
historyItem.innerHTML =
'<strong>' + item.project + '</strong>' +
'<span>' + item.total + '€</span>' +
'<small>' + item.hours + ' hours × ' + item.rate + '€/h · ' + item.date + '</small>';
historyList.appendChild(historyItem);
});
}
form.addEventListener("submit", function (event) {
event.preventDefault();
const total = calculateTotal();
const project = projectInput.value.trim() || "Untitled estimate";
history.unshift({
id: String(Date.now()),
project: project,
hours: Number(hoursInput.value) || 0,
rate: Number(rateInput.value) || 0,
total: total,
date: new Date().toLocaleDateString()
});
history = history.slice(0, 6);
saveHistory();
renderHistory();
updateCurrentTotal();
});
hoursInput.addEventListener("input", updateCurrentTotal);
rateInput.addEventListener("input", updateCurrentTotal);
clearButton.addEventListener("click", function () {
history = [];
localStorage.removeItem(storageKey);
renderHistory();
});
loadHistory();
renderHistory();
updateCurrentTotal();
})();
<div class="vb-storage-fourteen-demo">
<div class="vb-storage-fourteen-app" data-vb-storage-fourteen>
<div class="vb-storage-fourteen-calc">
<span class="vb-storage-fourteen-kicker">Example 14</span>
<h3>Saved Calculator History</h3>
<p>Calculate a project estimate and save every result in localStorage for later comparison.</p>
<form data-calc-form class="vb-storage-fourteen-form">
<label>
<span>Project name</span>
<input type="text" data-project-name placeholder="Landing page build">
</label>
<div class="vb-storage-fourteen-fields">
<label>
<span>Hours</span>
<input type="number" data-hours min="1" value="12">
</label>
<label>
<span>Hourly rate (€)</span>
<input type="number" data-rate min="1" value="45">
</label>
</div>
<button type="submit">Calculate Estimate</button>
</form>
<div class="vb-storage-fourteen-total">
<span>Current estimate</span>
<strong data-current-total>540€</strong>
</div>
</div>
<div class="vb-storage-fourteen-history">
<div class="vb-storage-fourteen-history-head">
<strong>Saved History</strong>
<button type="button" data-clear-history>Clear</button>
</div>
<div class="vb-storage-fourteen-list" data-history-list>
<p class="vb-storage-fourteen-empty">No saved calculations yet.</p>
</div>
</div>
</div>
</div>
.vb-storage-fourteen-demo,
.vb-storage-fourteen-demo * {
box-sizing: border-box;
}
.vb-storage-fourteen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(249, 115, 22, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(37, 99, 235, 0.16), transparent 34%),
linear-gradient(135deg, #fff7ed 0%, #eff6ff 55%, #ffffff 100%) !important;
border: 1px solid rgba(249, 115, 22, 0.18);
box-shadow: 0 28px 80px rgba(154, 52, 18, 0.10);
}
.vb-storage-fourteen-app {
display: grid;
grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-fourteen-calc,
.vb-storage-fourteen-history {
min-width: 0;
}
.vb-storage-fourteen-calc {
display: grid;
gap: 16px;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #111827;
}
.vb-storage-fourteen-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(249, 115, 22, 0.16);
color: #fed7aa !important;
-webkit-text-fill-color: #fed7aa !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-fourteen-calc h3 {
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 64px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-fourteen-calc p {
margin: 0 !important;
color: #d1d5db !important;
-webkit-text-fill-color: #d1d5db !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-fourteen-form {
display: grid;
gap: 12px;
}
.vb-storage-fourteen-form label {
display: grid;
gap: 7px;
}
.vb-storage-fourteen-form label span {
color: #fed7aa !important;
-webkit-text-fill-color: #fed7aa !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-fourteen-fields {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.vb-storage-fourteen-form input {
width: 100%;
min-height: 50px;
padding: 0 15px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 16px;
background: rgba(255,255,255,0.09);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 15px;
font-weight: 750;
outline: none;
}
.vb-storage-fourteen-form input::placeholder {
color: #9ca3af;
-webkit-text-fill-color: #9ca3af;
}
.vb-storage-fourteen-form input:focus {
border-color: rgba(249, 115, 22, 0.70);
box-shadow: 0 0 0 4px rgba(249, 115, 22, 0.12);
}
.vb-storage-fourteen-form button {
min-height: 50px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #f97316, #2563eb);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}
.vb-storage-fourteen-total {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
padding: 16px;
border-radius: 22px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-fourteen-total span {
color: #fed7aa !important;
-webkit-text-fill-color: #fed7aa !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-fourteen-total strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 34px;
line-height: 1;
font-weight: 950;
}
.vb-storage-fourteen-history {
display: grid;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-fourteen-history-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-fourteen-history-head strong {
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-fourteen-history-head button {
min-height: 38px;
padding: 0 13px;
border: 0;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 12px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-fourteen-list {
display: grid;
gap: 10px;
min-height: 340px;
}
.vb-storage-fourteen-empty {
display: grid;
place-items: center;
min-height: 340px;
margin: 0 !important;
border: 1px dashed rgba(148, 163, 184, 0.55);
border-radius: 22px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-fourteen-item {
display: grid;
gap: 7px;
padding: 14px;
border-radius: 18px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}
.vb-storage-fourteen-item strong {
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 16px;
line-height: 1.2;
font-weight: 950;
}
.vb-storage-fourteen-item span {
color: #2563eb !important;
-webkit-text-fill-color: #2563eb !important;
font-size: 22px;
line-height: 1;
font-weight: 950;
}
.vb-storage-fourteen-item small {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 750;
}
@media (max-width: 920px) {
.vb-storage-fourteen-app {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-fourteen-fields {
grid-template-columns: 1fr;
}
.vb-storage-fourteen-calc h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-fourteen-total {
align-items: flex-start;
flex-direction: column;
}
}
This calculator history localStorage example is useful for price calculators, quote estimators, loan calculators, discount calculators, project calculators, service estimate forms, and browser-based calculation tools.
Saving reading progress with localStorage is useful for blogs, documentation pages, tutorials, online courses, long-form guides, knowledge bases, and article websites. It helps readers continue from where they left off after returning to a page.
This example simulates a long article area with section buttons. JavaScript saves the last selected article section in localStorage, updates the reading progress indicator, and restores the same section after refresh.
Select article sections and refresh the page. localStorage restores the last section you were reading.
This section introduces the topic and explains why saving reading progress can improve long-form content experiences.
This section explains how a page can use JavaScript, section buttons, and localStorage to remember the reader’s last position.
This section could contain code examples, screenshots, tutorial steps, videos, or detailed learning material.
This section closes the guide and lets the reader return later without losing where they stopped.
(function () {
const wrapper = document.querySelector("[data-vb-storage-fifteen]");
if (!wrapper) return;
const storageKey = "vbStorageFifteenReadingSection";
const buttons = Array.from(wrapper.querySelectorAll("[data-section-button]"));
const panels = Array.from(wrapper.querySelectorAll("[data-section-panel]"));
const progressBar = wrapper.querySelector("[data-reading-progress]");
const progressLabel = wrapper.querySelector("[data-progress-label]");
const resetButton = wrapper.querySelector("[data-reset-reading]");
function activateSection(sectionKey) {
const activeIndex = buttons.findIndex(function (button) {
return button.getAttribute("data-section-button") === sectionKey;
});
const safeIndex = activeIndex >= 0 ? activeIndex : 0;
const safeKey = buttons[safeIndex].getAttribute("data-section-button");
const percent = Math.round(((safeIndex + 1) / buttons.length) * 100);
buttons.forEach(function (button) {
button.classList.toggle("is-active", button.getAttribute("data-section-button") === safeKey);
});
panels.forEach(function (panel) {
panel.classList.toggle("is-active", panel.getAttribute("data-section-panel") === safeKey);
});
progressBar.style.width = percent + "%";
progressLabel.textContent = percent + "% complete";
localStorage.setItem(storageKey, safeKey);
}
buttons.forEach(function (button) {
button.addEventListener("click", function () {
activateSection(button.getAttribute("data-section-button"));
});
});
resetButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
activateSection("intro");
});
activateSection(localStorage.getItem(storageKey) || "intro");
})();
<div class="vb-storage-fifteen-demo">
<div class="vb-storage-fifteen-reader" data-vb-storage-fifteen>
<div class="vb-storage-fifteen-head">
<span class="vb-storage-fifteen-kicker">Example 15</span>
<h3>Continue Reading Progress</h3>
<p>Select article sections and refresh the page. localStorage restores the last section you were reading.</p>
</div>
<div class="vb-storage-fifteen-layout">
<aside class="vb-storage-fifteen-sidebar">
<strong>Article Sections</strong>
<button type="button" data-section-button="intro" class="is-active">1. Introduction</button>
<button type="button" data-section-button="setup">2. Setup</button>
<button type="button" data-section-button="examples">3. Examples</button>
<button type="button" data-section-button="summary">4. Summary</button>
<div class="vb-storage-fifteen-progress">
<span>Reading progress</span>
<div><i data-reading-progress></i></div>
<small data-progress-label>25% complete</small>
</div>
</aside>
<article class="vb-storage-fifteen-content">
<section data-section-panel="intro" class="is-active">
<span>Section 01</span>
<h4>Introduction</h4>
<p>This section introduces the topic and explains why saving reading progress can improve long-form content experiences.</p>
</section>
<section data-section-panel="setup">
<span>Section 02</span>
<h4>Setup</h4>
<p>This section explains how a page can use JavaScript, section buttons, and localStorage to remember the reader’s last position.</p>
</section>
<section data-section-panel="examples">
<span>Section 03</span>
<h4>Examples</h4>
<p>This section could contain code examples, screenshots, tutorial steps, videos, or detailed learning material.</p>
</section>
<section data-section-panel="summary">
<span>Section 04</span>
<h4>Summary</h4>
<p>This section closes the guide and lets the reader return later without losing where they stopped.</p>
</section>
</article>
</div>
<button type="button" class="vb-storage-fifteen-reset" data-reset-reading>Reset Reading Progress</button>
</div>
</div>
.vb-storage-fifteen-demo,
.vb-storage-fifteen-demo * {
box-sizing: border-box;
}
.vb-storage-fifteen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(6, 182, 212, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(124, 58, 237, 0.14), transparent 34%),
linear-gradient(135deg, #ecfeff 0%, #f5f3ff 55%, #ffffff 100%) !important;
border: 1px solid rgba(6, 182, 212, 0.18);
box-shadow: 0 28px 80px rgba(14, 116, 144, 0.10);
}
.vb-storage-fifteen-reader {
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-fifteen-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-fifteen-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #cffafe;
color: #0e7490 !important;
-webkit-text-fill-color: #0e7490 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-fifteen-head h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-fifteen-head p {
max-width: 760px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-fifteen-layout {
display: grid;
grid-template-columns: 280px minmax(0, 1fr);
gap: 18px;
align-items: stretch;
}
.vb-storage-fifteen-sidebar {
display: grid;
align-content: start;
gap: 10px;
padding: 18px;
border-radius: 28px;
background: #0f172a;
}
.vb-storage-fifteen-sidebar strong {
margin-bottom: 6px;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 22px;
line-height: 1.15;
font-weight: 950;
}
.vb-storage-fifteen-sidebar button {
min-height: 44px;
padding: 10px 13px;
border: 0;
border-radius: 16px;
background: rgba(255,255,255,0.08);
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 13px;
font-weight: 850;
text-align: left;
cursor: pointer;
}
.vb-storage-fifteen-sidebar button.is-active {
background: linear-gradient(135deg, #06b6d4, #7c3aed);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-fifteen-progress {
display: grid;
gap: 8px;
margin-top: 12px;
padding: 14px;
border-radius: 20px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.10);
}
.vb-storage-fifteen-progress span,
.vb-storage-fifteen-progress small {
color: #e0f2fe !important;
-webkit-text-fill-color: #e0f2fe !important;
font-size: 12px;
font-weight: 850;
}
.vb-storage-fifteen-progress div {
height: 10px;
overflow: hidden;
border-radius: 999px;
background: rgba(255,255,255,0.12);
}
.vb-storage-fifteen-progress i {
display: block;
width: 25%;
height: 100%;
border-radius: 999px;
background: linear-gradient(135deg, #06b6d4, #a78bfa);
transition: width 0.25s ease;
}
.vb-storage-fifteen-content {
min-height: 420px;
border-radius: 28px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
overflow: hidden;
}
.vb-storage-fifteen-content section {
display: none;
min-height: 420px;
padding: clamp(24px, 5vw, 54px);
background:
radial-gradient(circle at 90% 12%, rgba(6, 182, 212, 0.16), transparent 34%),
linear-gradient(135deg, #ffffff, #f8fafc) !important;
}
.vb-storage-fifteen-content section.is-active {
display: grid;
align-content: center;
gap: 14px;
}
.vb-storage-fifteen-content section span {
display: inline-flex;
justify-self: start;
padding: 8px 11px;
border-radius: 999px;
background: #cffafe;
color: #0e7490 !important;
-webkit-text-fill-color: #0e7490 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.10em;
text-transform: uppercase;
}
.vb-storage-fifteen-content section h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(34px, 5vw, 58px) !important;
line-height: 0.98 !important;
font-weight: 950 !important;
letter-spacing: -0.07em;
}
.vb-storage-fifteen-content section p {
max-width: 640px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 17px;
line-height: 1.75;
font-weight: 650;
}
.vb-storage-fifteen-reset {
min-height: 42px;
margin-top: 16px;
padding: 0 14px;
border: 0;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 12px;
font-weight: 950;
cursor: pointer;
}
@media (max-width: 860px) {
.vb-storage-fifteen-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-fifteen-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-fifteen-reset {
width: 100%;
}
}
This continue reading localStorage example is useful for long blog posts, documentation pages, online lessons, tutorials, course platforms, knowledge bases, and step-by-step educational content.
Saving accordion open state with localStorage is useful for FAQ sections, product detail panels, support centers, documentation pages, settings panels, and course lessons. When a visitor opens a panel and refreshes the page, the same accordion item can stay open.
This example saves the currently open accordion item in localStorage. JavaScript updates the active panel when a button is clicked, stores the selected panel key, and restores the same open panel after refresh.
Open an FAQ item and refresh the page. localStorage restores the same open accordion panel.
Shipping options can be displayed here. This panel stays open after refresh because the active accordion key is saved in localStorage.
You can use this panel for payment details, invoice options, card payments, bank links, or custom ecommerce checkout information.
This panel can include support information, response times, help center links, documentation, or contact details.
Yes. The same localStorage logic can be used for product accordions, settings panels, documentation sections, and FAQ blocks.
(function () {
const wrapper = document.querySelector("[data-vb-storage-sixteen]");
if (!wrapper) return;
const storageKey = "vbStorageSixteenAccordion";
const items = wrapper.querySelectorAll("[data-accordion-item]");
const buttons = wrapper.querySelectorAll("[data-accordion-button]");
const savedPanelLabel = wrapper.querySelector("[data-saved-panel]");
const resetButton = wrapper.querySelector("[data-reset-accordion]");
function openPanel(panelKey) {
items.forEach(function (item) {
item.classList.toggle("is-active", item.getAttribute("data-accordion-item") === panelKey);
});
savedPanelLabel.textContent = panelKey;
localStorage.setItem(storageKey, panelKey);
}
buttons.forEach(function (button) {
button.addEventListener("click", function () {
openPanel(button.getAttribute("data-accordion-button"));
});
});
resetButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
openPanel("shipping");
});
openPanel(localStorage.getItem(storageKey) || "shipping");
})();
<div class="vb-storage-sixteen-demo">
<div class="vb-storage-sixteen-faq" data-vb-storage-sixteen>
<div class="vb-storage-sixteen-head">
<span class="vb-storage-sixteen-kicker">Example 16</span>
<h3>Saved Accordion State</h3>
<p>Open an FAQ item and refresh the page. localStorage restores the same open accordion panel.</p>
</div>
<div class="vb-storage-sixteen-list">
<div class="vb-storage-sixteen-item is-active" data-accordion-item="shipping">
<button type="button" data-accordion-button="shipping">
<span>How does shipping work?</span>
<strong>+</strong>
</button>
<div class="vb-storage-sixteen-panel">
<p>Shipping options can be displayed here. This panel stays open after refresh because the active accordion key is saved in localStorage.</p>
</div>
</div>
<div class="vb-storage-sixteen-item" data-accordion-item="payment">
<button type="button" data-accordion-button="payment">
<span>Which payment methods are available?</span>
<strong>+</strong>
</button>
<div class="vb-storage-sixteen-panel">
<p>You can use this panel for payment details, invoice options, card payments, bank links, or custom ecommerce checkout information.</p>
</div>
</div>
<div class="vb-storage-sixteen-item" data-accordion-item="support">
<button type="button" data-accordion-button="support">
<span>Do you offer support?</span>
<strong>+</strong>
</button>
<div class="vb-storage-sixteen-panel">
<p>This panel can include support information, response times, help center links, documentation, or contact details.</p>
</div>
</div>
<div class="vb-storage-sixteen-item" data-accordion-item="custom">
<button type="button" data-accordion-button="custom">
<span>Can this be customized?</span>
<strong>+</strong>
</button>
<div class="vb-storage-sixteen-panel">
<p>Yes. The same localStorage logic can be used for product accordions, settings panels, documentation sections, and FAQ blocks.</p>
</div>
</div>
</div>
<div class="vb-storage-sixteen-status">
Saved open panel: <strong data-saved-panel>shipping</strong>
<button type="button" data-reset-accordion>Reset</button>
</div>
</div>
</div>
.vb-storage-sixteen-demo,
.vb-storage-sixteen-demo * {
box-sizing: border-box;
}
.vb-storage-sixteen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(16, 185, 129, 0.15), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #ecfdf5 56%, #ffffff 100%) !important;
border: 1px solid rgba(59, 130, 246, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-sixteen-faq {
max-width: 960px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-sixteen-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-sixteen-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-sixteen-head h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-sixteen-head p {
max-width: 760px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-sixteen-list {
display: grid;
gap: 12px;
}
.vb-storage-sixteen-item {
overflow: hidden;
border: 1px solid rgba(148, 163, 184, 0.24);
border-radius: 22px;
background: #f8fafc;
transition: border-color 0.22s ease, box-shadow 0.22s ease;
}
.vb-storage-sixteen-item.is-active {
border-color: rgba(37, 99, 235, 0.55);
box-shadow: 0 16px 40px rgba(37, 99, 235, 0.10);
}
.vb-storage-sixteen-item button {
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
width: 100%;
min-height: 64px;
padding: 18px;
border: 0;
background: transparent;
cursor: pointer;
text-align: left;
}
.vb-storage-sixteen-item button span {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 18px;
line-height: 1.25;
font-weight: 950;
}
.vb-storage-sixteen-item button strong {
display: grid;
place-items: center;
flex: 0 0 auto;
width: 34px;
height: 34px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 20px;
line-height: 1;
font-weight: 950;
}
.vb-storage-sixteen-item.is-active button strong {
background: linear-gradient(135deg, #2563eb, #10b981);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
transform: rotate(45deg);
}
.vb-storage-sixteen-panel {
display: none;
padding: 0 18px 18px;
}
.vb-storage-sixteen-item.is-active .vb-storage-sixteen-panel {
display: block;
}
.vb-storage-sixteen-panel p {
margin: 0 !important;
padding: 16px;
border-radius: 18px;
background: #ffffff;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 15px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-sixteen-status {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
margin-top: 16px;
padding: 14px 16px;
border-radius: 20px;
background: #eff6ff;
color: #1e3a8a !important;
-webkit-text-fill-color: #1e3a8a !important;
font-size: 14px;
font-weight: 850;
}
.vb-storage-sixteen-status strong {
color: #047857 !important;
-webkit-text-fill-color: #047857 !important;
}
.vb-storage-sixteen-status button {
min-height: 38px;
padding: 0 13px;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 12px;
font-weight: 950;
cursor: pointer;
}
@media (max-width: 560px) {
.vb-storage-sixteen-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-sixteen-status button {
width: 100%;
}
}
This saved accordion state localStorage example is useful for FAQ sections, product information panels, checkout help blocks, documentation pages, support center categories, and dashboard settings panels.
Saving user preferences with localStorage is useful for dashboards, admin panels, SaaS apps, documentation websites, blog layouts, accessibility widgets, and custom website settings. It lets visitors keep interface choices such as font size, layout density, and accent style.
This example saves three interface preferences: text size, layout density, and accent color. JavaScript stores the settings object in localStorage, applies the choices instantly, and restores the same preferences after refresh.
This preview changes based on your saved localStorage preferences. It can be used for dashboard settings, accessibility controls, user accounts, or blog reading options.
(function () {
const wrapper = document.querySelector("[data-vb-storage-seventeen]");
if (!wrapper) return;
const storageKey = "vbStorageSeventeenPreferences";
const selects = wrapper.querySelectorAll("[data-preference]");
const resetButton = wrapper.querySelector("[data-reset-preferences]");
const summary = wrapper.querySelector("[data-preference-summary]");
const defaultPreferences = {
size: "medium",
density: "comfortable",
accent: "blue"
};
let preferences = Object.assign({}, defaultPreferences);
function savePreferences() {
localStorage.setItem(storageKey, JSON.stringify(preferences));
}
function loadPreferences() {
const savedPreferences = localStorage.getItem(storageKey);
if (!savedPreferences) return;
try {
const parsedPreferences = JSON.parse(savedPreferences);
preferences = Object.assign({}, defaultPreferences, parsedPreferences);
} catch (error) {
preferences = Object.assign({}, defaultPreferences);
localStorage.removeItem(storageKey);
}
}
function applyPreferences() {
wrapper.setAttribute("data-size", preferences.size);
wrapper.setAttribute("data-density", preferences.density);
wrapper.setAttribute("data-accent", preferences.accent);
selects.forEach(function (select) {
const key = select.getAttribute("data-preference");
select.value = preferences[key];
});
summary.textContent = preferences.size + " · " + preferences.density + " · " + preferences.accent;
savePreferences();
}
selects.forEach(function (select) {
select.addEventListener("change", function () {
const key = select.getAttribute("data-preference");
preferences[key] = select.value;
applyPreferences();
});
});
resetButton.addEventListener("click", function () {
preferences = Object.assign({}, defaultPreferences);
localStorage.removeItem(storageKey);
applyPreferences();
});
loadPreferences();
applyPreferences();
})();
<div class="vb-storage-seventeen-demo">
<div class="vb-storage-seventeen-app" data-vb-storage-seventeen data-size="medium" data-density="comfortable" data-accent="blue">
<aside class="vb-storage-seventeen-settings">
<span class="vb-storage-seventeen-kicker">Example 17</span>
<h3>Saved User Preferences</h3>
<p>Change the settings and refresh the page. localStorage restores your preferred interface style.</p>
<label>
<span>Text size</span>
<select data-preference="size">
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="large">Large</option>
</select>
</label>
<label>
<span>Layout density</span>
<select data-preference="density">
<option value="compact">Compact</option>
<option value="comfortable">Comfortable</option>
<option value="spacious">Spacious</option>
</select>
</label>
<label>
<span>Accent color</span>
<select data-preference="accent">
<option value="blue">Blue</option>
<option value="green">Green</option>
<option value="purple">Purple</option>
</select>
</label>
<button type="button" data-reset-preferences>Reset Preferences</button>
</aside>
<section class="vb-storage-seventeen-preview">
<div class="vb-storage-seventeen-preview-top">
<span>Dashboard Preview</span>
<strong data-preference-summary>medium · comfortable · blue</strong>
</div>
<div class="vb-storage-seventeen-card">
<h4>Saved Interface Settings</h4>
<p>This preview changes based on your saved localStorage preferences. It can be used for dashboard settings, accessibility controls, user accounts, or blog reading options.</p>
</div>
<div class="vb-storage-seventeen-grid">
<div>
<span>Preference</span>
<strong>Text size</strong>
</div>
<div>
<span>Preference</span>
<strong>Density</strong>
</div>
<div>
<span>Preference</span>
<strong>Accent</strong>
</div>
</div>
</section>
</div>
</div>
.vb-storage-seventeen-demo,
.vb-storage-seventeen-demo * {
box-sizing: border-box;
}
.vb-storage-seventeen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.14), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #faf5ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-seventeen-app {
display: grid;
grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-seventeen-settings,
.vb-storage-seventeen-preview {
min-width: 0;
}
.vb-storage-seventeen-settings {
display: grid;
align-content: start;
gap: 13px;
padding: clamp(18px, 3vw, 24px);
border-radius: 28px;
background: #0f172a;
}
.vb-storage-seventeen-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(96, 165, 250, 0.18);
color: #bfdbfe !important;
-webkit-text-fill-color: #bfdbfe !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-seventeen-settings h3 {
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(34px, 5vw, 58px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.07em;
}
.vb-storage-seventeen-settings p {
margin: 0 0 8px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 15px;
line-height: 1.65;
font-weight: 650;
}
.vb-storage-seventeen-settings label {
display: grid;
gap: 7px;
}
.vb-storage-seventeen-settings label span {
color: #dbeafe !important;
-webkit-text-fill-color: #dbeafe !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-seventeen-settings select {
width: 100%;
min-height: 46px;
padding: 0 13px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 15px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
font-weight: 750;
outline: none;
}
.vb-storage-seventeen-settings button {
min-height: 44px;
margin-top: 4px;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-seventeen-preview {
display: grid;
gap: 16px;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-seventeen-preview-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.vb-storage-seventeen-preview-top span {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 13px;
font-weight: 900;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.vb-storage-seventeen-preview-top strong {
color: #2563eb !important;
-webkit-text-fill-color: #2563eb !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-seventeen-card {
padding: clamp(20px, 4vw, 34px);
border-radius: 26px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}
.vb-storage-seventeen-card h4 {
margin: 0 0 12px !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 34px !important;
line-height: 1.05 !important;
font-weight: 950 !important;
letter-spacing: -0.055em;
}
.vb-storage-seventeen-card p {
max-width: 650px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-seventeen-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.vb-storage-seventeen-grid div {
padding: 16px;
border-radius: 20px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-seventeen-grid span {
display: block;
margin-bottom: 7px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-seventeen-grid strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 18px;
font-weight: 950;
}
.vb-storage-seventeen-app[data-size="small"] .vb-storage-seventeen-card p {
font-size: 14px;
}
.vb-storage-seventeen-app[data-size="medium"] .vb-storage-seventeen-card p {
font-size: 16px;
}
.vb-storage-seventeen-app[data-size="large"] .vb-storage-seventeen-card p {
font-size: 19px;
}
.vb-storage-seventeen-app[data-density="compact"] .vb-storage-seventeen-card,
.vb-storage-seventeen-app[data-density="compact"] .vb-storage-seventeen-grid div {
padding: 14px;
}
.vb-storage-seventeen-app[data-density="comfortable"] .vb-storage-seventeen-card {
padding: 28px;
}
.vb-storage-seventeen-app[data-density="spacious"] .vb-storage-seventeen-card,
.vb-storage-seventeen-app[data-density="spacious"] .vb-storage-seventeen-grid div {
padding: 34px;
}
.vb-storage-seventeen-app[data-accent="blue"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="blue"] .vb-storage-seventeen-grid strong {
color: #2563eb !important;
-webkit-text-fill-color: #2563eb !important;
}
.vb-storage-seventeen-app[data-accent="green"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="green"] .vb-storage-seventeen-grid strong {
color: #059669 !important;
-webkit-text-fill-color: #059669 !important;
}
.vb-storage-seventeen-app[data-accent="purple"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="purple"] .vb-storage-seventeen-grid strong {
color: #7c3aed !important;
-webkit-text-fill-color: #7c3aed !important;
}
@media (max-width: 920px) {
.vb-storage-seventeen-app {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-seventeen-grid {
grid-template-columns: 1fr;
}
.vb-storage-seventeen-settings h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This user preferences localStorage example is useful for dashboards, admin panels, user account settings, accessibility widgets, SaaS interfaces, documentation pages, and blog reading preference controls.
Saving a discount code with localStorage is useful for ecommerce landing pages, product checkout demos, pricing sections, cart pages, coupon banners, and sales campaigns. It lets a visitor apply a coupon and keep that discount visible after refreshing the page.
This example applies a discount code to a simple order summary. JavaScript saves the applied coupon in localStorage, recalculates the total, shows discount feedback, and restores the coupon after refresh.
Apply the code SAVE20, refresh the page, and localStorage keeps the discount active.
(function () {
const wrapper = document.querySelector("[data-vb-storage-eighteen]");
if (!wrapper) return;
const storageKey = "vbStorageEighteenCoupon";
const form = wrapper.querySelector("[data-coupon-form]");
const input = wrapper.querySelector("[data-coupon-input]");
const message = wrapper.querySelector("[data-coupon-message]");
const badge = wrapper.querySelector("[data-coupon-badge]");
const discountValue = wrapper.querySelector("[data-discount-value]");
const orderTotal = wrapper.querySelector("[data-order-total]");
const removeButton = wrapper.querySelector("[data-remove-coupon]");
const baseTotal = 200;
const validCoupon = "SAVE20";
const discountPercent = 20;
function applyCoupon(code) {
const normalizedCode = (code || "").trim().toUpperCase();
const isValid = normalizedCode === validCoupon;
const discount = isValid ? Math.round(baseTotal * discountPercent / 100) : 0;
const total = baseTotal - discount;
input.value = normalizedCode;
discountValue.textContent = "-" + discount + "€";
orderTotal.textContent = total + "€";
if (isValid) {
localStorage.setItem(storageKey, normalizedCode);
message.textContent = "Coupon status: SAVE20 applied and saved in localStorage.";
badge.textContent = "SAVE20 active";
badge.classList.add("is-active");
} else {
localStorage.removeItem(storageKey);
message.textContent = normalizedCode ? "Coupon status: invalid code." : "Coupon status: no code applied.";
badge.textContent = "No coupon";
badge.classList.remove("is-active");
}
}
form.addEventListener("submit", function (event) {
event.preventDefault();
applyCoupon(input.value);
});
removeButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
input.value = "";
applyCoupon("");
});
applyCoupon(localStorage.getItem(storageKey) || "");
})();
<div class="vb-storage-eighteen-demo">
<div class="vb-storage-eighteen-checkout" data-vb-storage-eighteen>
<div class="vb-storage-eighteen-info">
<span class="vb-storage-eighteen-kicker">Example 18</span>
<h3>Saved Discount Code</h3>
<p>Apply the code <strong>SAVE20</strong>, refresh the page, and localStorage keeps the discount active.</p>
<form class="vb-storage-eighteen-form" data-coupon-form>
<input type="text" data-coupon-input placeholder="Enter coupon code">
<button type="submit">Apply Code</button>
</form>
<div class="vb-storage-eighteen-message" data-coupon-message>
Coupon status: no code applied.
</div>
</div>
<div class="vb-storage-eighteen-summary">
<div class="vb-storage-eighteen-summary-head">
<strong>Order Summary</strong>
<span data-coupon-badge>No coupon</span>
</div>
<div class="vb-storage-eighteen-line">
<span>Website template</span>
<strong>120€</strong>
</div>
<div class="vb-storage-eighteen-line">
<span>Setup service</span>
<strong>80€</strong>
</div>
<div class="vb-storage-eighteen-line vb-storage-eighteen-discount">
<span>Discount</span>
<strong data-discount-value>0€</strong>
</div>
<div class="vb-storage-eighteen-total">
<span>Total</span>
<strong data-order-total>200€</strong>
</div>
<button type="button" data-remove-coupon>Remove Saved Coupon</button>
</div>
</div>
</div>
.vb-storage-eighteen-demo,
.vb-storage-eighteen-demo * {
box-sizing: border-box;
}
.vb-storage-eighteen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
linear-gradient(135deg, #ecfdf5 0%, #fffbeb 56%, #ffffff 100%) !important;
border: 1px solid rgba(16, 185, 129, 0.18);
box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}
.vb-storage-eighteen-checkout {
display: grid;
grid-template-columns: minmax(0, 0.9fr) minmax(320px, 420px);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-eighteen-info,
.vb-storage-eighteen-summary {
min-width: 0;
}
.vb-storage-eighteen-info {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #0f172a;
}
.vb-storage-eighteen-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(16, 185, 129, 0.16);
color: #a7f3d0 !important;
-webkit-text-fill-color: #a7f3d0 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-eighteen-info h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-eighteen-info p {
max-width: 560px;
margin: 0 0 22px !important;
color: #d1d5db !important;
-webkit-text-fill-color: #d1d5db !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-eighteen-info p strong {
color: #fde68a !important;
-webkit-text-fill-color: #fde68a !important;
}
.vb-storage-eighteen-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
margin-bottom: 14px;
}
.vb-storage-eighteen-form input {
min-width: 0;
min-height: 50px;
padding: 0 15px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 999px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
font-weight: 750;
outline: none;
}
.vb-storage-eighteen-form input::placeholder {
color: #9ca3af;
-webkit-text-fill-color: #9ca3af;
}
.vb-storage-eighteen-form input:focus {
border-color: rgba(16, 185, 129, 0.70);
box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.12);
}
.vb-storage-eighteen-form button {
min-height: 50px;
padding: 0 16px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #10b981, #f59e0b);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-eighteen-message {
padding: 13px 15px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
color: #d1fae5 !important;
-webkit-text-fill-color: #d1fae5 !important;
font-size: 14px;
line-height: 1.45;
font-weight: 800;
}
.vb-storage-eighteen-summary {
display: grid;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-eighteen-summary-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-eighteen-summary-head strong {
color: #111827 !important;
-webkit-text-fill-color: #111827 !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-eighteen-summary-head span {
padding: 7px 10px;
border-radius: 999px;
background: #e5e7eb;
color: #374151 !important;
-webkit-text-fill-color: #374151 !important;
font-size: 12px;
font-weight: 950;
}
.vb-storage-eighteen-summary-head span.is-active {
background: #dcfce7;
color: #15803d !important;
-webkit-text-fill-color: #15803d !important;
}
.vb-storage-eighteen-line,
.vb-storage-eighteen-total {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
padding: 14px;
border-radius: 18px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.18);
}
.vb-storage-eighteen-line span,
.vb-storage-eighteen-line strong {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 14px;
font-weight: 850;
}
.vb-storage-eighteen-discount span,
.vb-storage-eighteen-discount strong {
color: #059669 !important;
-webkit-text-fill-color: #059669 !important;
}
.vb-storage-eighteen-total {
background: #0f172a;
}
.vb-storage-eighteen-total span {
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 900;
}
.vb-storage-eighteen-total strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 34px;
line-height: 1;
font-weight: 950;
}
.vb-storage-eighteen-summary > button {
min-height: 44px;
border: 0;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
@media (max-width: 900px) {
.vb-storage-eighteen-checkout {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-eighteen-form {
grid-template-columns: 1fr;
}
.vb-storage-eighteen-info h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This discount code localStorage example is useful for ecommerce checkout pages, coupon banners, landing page offers, pricing tables, cart demos, product sales pages, and WooCommerce-style promotional features.
If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.
A remember me login form with localStorage is a very common JavaScript example for login pages, account forms, dashboard prototypes, and membership websites. In real projects, passwords should never be stored in localStorage, but saving a harmless email or username preference is a practical UI pattern.
This example saves only the email address when the “Remember me” checkbox is enabled. JavaScript restores the email after refresh, updates the saved status, and clears the stored email when the checkbox is turned off.
Save only the email address in localStorage. Passwords are never stored in this demo.
(function () {
const wrapper = document.querySelector("[data-vb-storage-nineteen]");
if (!wrapper) return;
const storageKey = "vbStorageNineteenRememberEmail";
const form = wrapper.querySelector("[data-login-form]");
const emailInput = wrapper.querySelector("[data-login-email]");
const passwordInput = wrapper.querySelector("[data-login-password]");
const rememberCheckbox = wrapper.querySelector("[data-remember-email]");
const status = wrapper.querySelector("[data-login-status]");
const clearButton = wrapper.querySelector("[data-clear-login]");
function updateStatus() {
const savedEmail = localStorage.getItem(storageKey);
if (savedEmail) {
status.textContent = "Saved email: " + savedEmail;
emailInput.value = savedEmail;
rememberCheckbox.checked = true;
} else {
status.textContent = "Email not saved yet.";
rememberCheckbox.checked = false;
}
}
function saveEmailIfAllowed() {
const email = emailInput.value.trim();
if (rememberCheckbox.checked && email) {
localStorage.setItem(storageKey, email);
}
if (!rememberCheckbox.checked) {
localStorage.removeItem(storageKey);
}
updateStatus();
}
rememberCheckbox.addEventListener("change", saveEmailIfAllowed);
emailInput.addEventListener("input", function () {
if (rememberCheckbox.checked) {
saveEmailIfAllowed();
}
});
form.addEventListener("submit", function (event) {
event.preventDefault();
saveEmailIfAllowed();
passwordInput.value = "";
status.textContent = rememberCheckbox.checked
? "Demo login complete. Email preference is saved."
: "Demo login complete. Email was not saved.";
});
clearButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
emailInput.value = "";
passwordInput.value = "";
updateStatus();
});
updateStatus();
})();
<div class="vb-storage-nineteen-demo">
<div class="vb-storage-nineteen-login" data-vb-storage-nineteen>
<div class="vb-storage-nineteen-info">
<span class="vb-storage-nineteen-kicker">Example 19</span>
<h3>Remember Me Login</h3>
<p>Save only the email address in localStorage. Passwords are never stored in this demo.</p>
<div class="vb-storage-nineteen-status" data-login-status>Email not saved yet.</div>
</div>
<form class="vb-storage-nineteen-form" data-login-form>
<label>
<span>Email address</span>
<input type="email" data-login-email placeholder="alex@example.com">
</label>
<label>
<span>Password</span>
<input type="password" data-login-password placeholder="Password is not saved">
</label>
<label class="vb-storage-nineteen-check">
<input type="checkbox" data-remember-email>
<span>Remember my email on this device</span>
</label>
<button type="submit">Demo Login</button>
<button type="button" class="vb-storage-nineteen-clear" data-clear-login>Clear Saved Email</button>
<p class="vb-storage-nineteen-note">Security note: this demo saves only the email address, never the password.</p>
</form>
</div>
</div>
.vb-storage-nineteen-demo,
.vb-storage-nineteen-demo * {
box-sizing: border-box;
}
.vb-storage-nineteen-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #ecfeff 56%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-nineteen-login {
display: grid;
grid-template-columns: minmax(0, 0.95fr) minmax(320px, 430px);
gap: 22px;
max-width: 1100px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #0f172a;
box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}
.vb-storage-nineteen-info,
.vb-storage-nineteen-form {
min-width: 0;
}
.vb-storage-nineteen-info {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
}
.vb-storage-nineteen-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(59, 130, 246, 0.18);
color: #bfdbfe !important;
-webkit-text-fill-color: #bfdbfe !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-nineteen-info h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-nineteen-info p {
max-width: 560px;
margin: 0 0 22px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-nineteen-status {
display: inline-flex;
align-self: flex-start;
padding: 13px 15px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
color: #e0f2fe !important;
-webkit-text-fill-color: #e0f2fe !important;
font-size: 14px;
line-height: 1.45;
font-weight: 850;
}
.vb-storage-nineteen-form {
display: grid;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-nineteen-form label {
display: grid;
gap: 7px;
}
.vb-storage-nineteen-form label > span {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-nineteen-form input[type="email"],
.vb-storage-nineteen-form input[type="password"] {
width: 100%;
min-height: 50px;
padding: 0 15px;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #f8fafc;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
font-weight: 700;
outline: none;
}
.vb-storage-nineteen-form input:focus {
border-color: rgba(37, 99, 235, 0.74);
box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}
.vb-storage-nineteen-check {
display: grid !important;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: 10px !important;
padding: 12px;
border-radius: 16px;
background: #eff6ff;
}
.vb-storage-nineteen-check input {
width: 18px;
height: 18px;
accent-color: #2563eb;
}
.vb-storage-nineteen-form button {
min-height: 48px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #2563eb, #0ea5e9);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-nineteen-clear {
background: #fee2e2 !important;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
.vb-storage-nineteen-note {
margin: 0 !important;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 13px;
line-height: 1.55;
font-weight: 700;
}
@media (max-width: 900px) {
.vb-storage-nineteen-login {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-nineteen-info h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This remember me localStorage example is useful for login pages, account forms, dashboard prototypes, membership websites, app interfaces, and JavaScript form preference demos. In production, only harmless preferences should be saved in localStorage.
Saving a dashboard layout with localStorage is useful for admin panels, SaaS dashboards, analytics pages, project management tools, ecommerce back offices, and user portals. It lets users choose which widgets are visible and keeps that layout after refresh.
This example lets users toggle dashboard widgets on or off. JavaScript saves the visible widget list in localStorage, updates the dashboard instantly, and restores the selected layout after page reload.
Monthly revenue overview
Website visits this month
Open project tasks
Unread client messages
(function () {
const wrapper = document.querySelector("[data-vb-storage-twenty]");
if (!wrapper) return;
const storageKey = "vbStorageTwentyDashboardLayout";
const toggles = wrapper.querySelectorAll("[data-widget-toggle]");
const widgets = wrapper.querySelectorAll("[data-dashboard-widget]");
const status = wrapper.querySelector("[data-layout-status]");
const resetButton = wrapper.querySelector("[data-reset-layout]");
const defaultVisibleWidgets = ["sales", "traffic", "tasks", "messages"];
let visibleWidgets = defaultVisibleWidgets.slice();
function saveLayout() {
localStorage.setItem(storageKey, JSON.stringify(visibleWidgets));
}
function loadLayout() {
const savedLayout = localStorage.getItem(storageKey);
if (!savedLayout) return;
try {
const parsedLayout = JSON.parse(savedLayout);
visibleWidgets = Array.isArray(parsedLayout) ? parsedLayout : defaultVisibleWidgets.slice();
} catch (error) {
visibleWidgets = defaultVisibleWidgets.slice();
localStorage.removeItem(storageKey);
}
}
function applyLayout() {
toggles.forEach(function (toggle) {
const key = toggle.getAttribute("data-widget-toggle");
toggle.checked = visibleWidgets.includes(key);
});
widgets.forEach(function (widget) {
const key = widget.getAttribute("data-dashboard-widget");
widget.classList.toggle("is-hidden", !visibleWidgets.includes(key));
});
status.textContent = visibleWidgets.length === 1
? "1 widget visible"
: visibleWidgets.length + " widgets visible";
saveLayout();
}
toggles.forEach(function (toggle) {
toggle.addEventListener("change", function () {
const key = toggle.getAttribute("data-widget-toggle");
if (toggle.checked && !visibleWidgets.includes(key)) {
visibleWidgets.push(key);
}
if (!toggle.checked) {
visibleWidgets = visibleWidgets.filter(function (item) {
return item !== key;
});
}
applyLayout();
});
});
resetButton.addEventListener("click", function () {
visibleWidgets = defaultVisibleWidgets.slice();
localStorage.removeItem(storageKey);
applyLayout();
});
loadLayout();
applyLayout();
})();
<div class="vb-storage-twenty-demo">
<div class="vb-storage-twenty-dashboard" data-vb-storage-twenty>
<aside class="vb-storage-twenty-controls">
<span class="vb-storage-twenty-kicker">Example 20</span>
<h3>Saved Dashboard Layout</h3>
<p>Choose which widgets should be visible. localStorage saves the dashboard layout after refresh.</p>
<label><input type="checkbox" data-widget-toggle="sales" checked> Sales widget</label>
<label><input type="checkbox" data-widget-toggle="traffic" checked> Traffic widget</label>
<label><input type="checkbox" data-widget-toggle="tasks" checked> Tasks widget</label>
<label><input type="checkbox" data-widget-toggle="messages" checked> Messages widget</label>
<button type="button" data-reset-layout>Reset Layout</button>
</aside>
<section class="vb-storage-twenty-preview">
<div class="vb-storage-twenty-preview-head">
<strong>Dashboard Preview</strong>
<span data-layout-status>4 widgets visible</span>
</div>
<div class="vb-storage-twenty-grid">
<article data-dashboard-widget="sales">
<span>Sales</span>
<strong>€12.4k</strong>
<p>Monthly revenue overview</p>
</article>
<article data-dashboard-widget="traffic">
<span>Traffic</span>
<strong>48.2k</strong>
<p>Website visits this month</p>
</article>
<article data-dashboard-widget="tasks">
<span>Tasks</span>
<strong>17</strong>
<p>Open project tasks</p>
</article>
<article data-dashboard-widget="messages">
<span>Messages</span>
<strong>9</strong>
<p>Unread client messages</p>
</article>
</div>
</section>
</div>
</div>
.vb-storage-twenty-demo,
.vb-storage-twenty-demo * {
box-sizing: border-box;
}
.vb-storage-twenty-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.14), transparent 34%),
linear-gradient(135deg, #eef2ff 0%, #f0fdfa 56%, #ffffff 100%) !important;
border: 1px solid rgba(99, 102, 241, 0.18);
box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}
.vb-storage-twenty-dashboard {
display: grid;
grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twenty-controls {
display: grid;
align-content: start;
gap: 12px;
min-width: 0;
padding: clamp(18px, 3vw, 24px);
border-radius: 28px;
background: #111827;
}
.vb-storage-twenty-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(129, 140, 248, 0.18);
color: #c7d2fe !important;
-webkit-text-fill-color: #c7d2fe !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twenty-controls h3 {
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(34px, 5vw, 58px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.07em;
}
.vb-storage-twenty-controls p {
margin: 0 0 8px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 15px;
line-height: 1.65;
font-weight: 650;
}
.vb-storage-twenty-controls label {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 10px;
align-items: center;
min-height: 44px;
padding: 10px 12px;
border-radius: 16px;
background: rgba(255,255,255,0.08);
color: #e5e7eb !important;
-webkit-text-fill-color: #e5e7eb !important;
font-size: 14px;
font-weight: 850;
}
.vb-storage-twenty-controls input {
width: 18px;
height: 18px;
accent-color: #6366f1;
}
.vb-storage-twenty-controls button {
min-height: 44px;
margin-top: 4px;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #4f46e5 !important;
-webkit-text-fill-color: #4f46e5 !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twenty-preview {
display: grid;
gap: 16px;
min-width: 0;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-twenty-preview-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.vb-storage-twenty-preview-head strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-twenty-preview-head span {
color: #4f46e5 !important;
-webkit-text-fill-color: #4f46e5 !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-twenty-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
min-height: 390px;
}
.vb-storage-twenty-grid article {
display: grid;
align-content: space-between;
min-height: 180px;
padding: 18px;
border-radius: 24px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}
.vb-storage-twenty-grid article.is-hidden {
display: none;
}
.vb-storage-twenty-grid article span {
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.09em;
text-transform: uppercase;
}
.vb-storage-twenty-grid article strong {
color: #4f46e5 !important;
-webkit-text-fill-color: #4f46e5 !important;
font-size: clamp(34px, 5vw, 54px);
line-height: 1;
font-weight: 950;
letter-spacing: -0.06em;
}
.vb-storage-twenty-grid article p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
}
@media (max-width: 920px) {
.vb-storage-twenty-dashboard {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-twenty-grid {
grid-template-columns: 1fr;
}
.vb-storage-twenty-controls h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This dashboard layout localStorage example is useful for admin panels, analytics dashboards, SaaS apps, ecommerce back offices, CRM interfaces, project management tools, and customizable user portals.
A Kanban board saved with localStorage is a practical JavaScript project for task management apps, project dashboards, content planning boards, CRM pipelines, and personal productivity tools. It teaches how to save grouped data and move items between columns.
This example lets users add a task, move tasks between To Do, Doing, and Done columns, delete tasks, and restore the full board after refresh. JavaScript stores the board data as a JSON object in localStorage.
Add tasks and move them between columns. localStorage restores the whole board after refresh.
(function () {
const wrapper = document.querySelector("[data-vb-storage-twentyone]");
if (!wrapper) return;
const storageKey = "vbStorageTwentyoneKanban";
const form = wrapper.querySelector("[data-kanban-form]");
const input = wrapper.querySelector("[data-kanban-input]");
const clearButton = wrapper.querySelector("[data-clear-board]");
const columns = {
todo: wrapper.querySelector('[data-task-column="todo"]'),
doing: wrapper.querySelector('[data-task-column="doing"]'),
done: wrapper.querySelector('[data-task-column="done"]')
};
const counts = {
todo: wrapper.querySelector('[data-count="todo"]'),
doing: wrapper.querySelector('[data-count="doing"]'),
done: wrapper.querySelector('[data-count="done"]')
};
let board = {
todo: [],
doing: [],
done: []
};
function saveBoard() {
localStorage.setItem(storageKey, JSON.stringify(board));
}
function loadBoard() {
const savedBoard = localStorage.getItem(storageKey);
if (!savedBoard) return;
try {
const parsedBoard = JSON.parse(savedBoard);
board = {
todo: Array.isArray(parsedBoard.todo) ? parsedBoard.todo : [],
doing: Array.isArray(parsedBoard.doing) ? parsedBoard.doing : [],
done: Array.isArray(parsedBoard.done) ? parsedBoard.done : []
};
} catch (error) {
localStorage.removeItem(storageKey);
}
}
function findTask(taskId) {
for (const columnName in board) {
const task = board[columnName].find(function (item) {
return item.id === taskId;
});
if (task) {
return {
task: task,
columnName: columnName
};
}
}
return null;
}
function renderBoard() {
Object.keys(columns).forEach(function (columnName) {
columns[columnName].innerHTML = "";
counts[columnName].textContent = board[columnName].length;
board[columnName].forEach(function (task) {
const card = document.createElement("div");
card.className = "vb-storage-twentyone-task";
card.innerHTML =
'<strong>' + task.text + '</strong>' +
'<div class="vb-storage-twentyone-actions">' +
'<button type="button" data-move-task="' + task.id + '" data-target-column="todo">To Do</button>' +
'<button type="button" data-move-task="' + task.id + '" data-target-column="doing">Doing</button>' +
'<button type="button" data-move-task="' + task.id + '" data-target-column="done">Done</button>' +
'<button type="button" data-delete-task="' + task.id + '">Delete</button>' +
'</div>';
columns[columnName].appendChild(card);
});
});
saveBoard();
}
function addTask(text) {
board.todo.unshift({
id: String(Date.now()),
text: text
});
renderBoard();
}
function moveTask(taskId, targetColumn) {
const found = findTask(taskId);
if (!found || found.columnName === targetColumn) return;
board[found.columnName] = board[found.columnName].filter(function (task) {
return task.id !== taskId;
});
board[targetColumn].unshift(found.task);
renderBoard();
}
function deleteTask(taskId) {
Object.keys(board).forEach(function (columnName) {
board[columnName] = board[columnName].filter(function (task) {
return task.id !== taskId;
});
});
renderBoard();
}
form.addEventListener("submit", function (event) {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
addTask(text);
input.value = "";
input.focus();
});
wrapper.addEventListener("click", function (event) {
const moveId = event.target.getAttribute("data-move-task");
const targetColumn = event.target.getAttribute("data-target-column");
const deleteId = event.target.getAttribute("data-delete-task");
if (moveId && targetColumn) {
moveTask(moveId, targetColumn);
}
if (deleteId) {
deleteTask(deleteId);
}
});
clearButton.addEventListener("click", function () {
board = {
todo: [],
doing: [],
done: []
};
localStorage.removeItem(storageKey);
renderBoard();
});
loadBoard();
renderBoard();
})();
<div class="vb-storage-twentyone-demo">
<div class="vb-storage-twentyone-board" data-vb-storage-twentyone>
<div class="vb-storage-twentyone-head">
<span class="vb-storage-twentyone-kicker">Example 21</span>
<h3>Saved Kanban Board</h3>
<p>Add tasks and move them between columns. localStorage restores the whole board after refresh.</p>
</div>
<form class="vb-storage-twentyone-form" data-kanban-form>
<input type="text" data-kanban-input placeholder="Add a new task...">
<button type="submit">Add Task</button>
<button type="button" data-clear-board>Clear Board</button>
</form>
<div class="vb-storage-twentyone-columns">
<section data-column="todo">
<h4>To Do <span data-count="todo">0</span></h4>
<div data-task-column="todo"></div>
</section>
<section data-column="doing">
<h4>Doing <span data-count="doing">0</span></h4>
<div data-task-column="doing"></div>
</section>
<section data-column="done">
<h4>Done <span data-count="done">0</span></h4>
<div data-task-column="done"></div>
</section>
</div>
</div>
</div>
.vb-storage-twentyone-demo,
.vb-storage-twentyone-demo * {
box-sizing: border-box;
}
.vb-storage-twentyone-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
linear-gradient(135deg, #f0f9ff 0%, #faf5ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(14, 165, 233, 0.18);
box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}
.vb-storage-twentyone-board {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #0f172a;
box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}
.vb-storage-twentyone-head {
display: grid;
gap: 12px;
margin-bottom: 20px;
}
.vb-storage-twentyone-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(14, 165, 233, 0.16);
color: #bae6fd !important;
-webkit-text-fill-color: #bae6fd !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentyone-head h3 {
max-width: 820px;
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentyone-head p {
max-width: 760px;
margin: 0 !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentyone-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
gap: 10px;
margin-bottom: 18px;
padding: 14px;
border-radius: 24px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentyone-form input {
min-width: 0;
min-height: 48px;
padding: 0 15px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 999px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
font-weight: 750;
outline: none;
}
.vb-storage-twentyone-form input::placeholder {
color: #9ca3af;
-webkit-text-fill-color: #9ca3af;
}
.vb-storage-twentyone-form button {
min-height: 48px;
padding: 0 15px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #0ea5e9, #9333ea);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyone-form button:last-child {
background: rgba(255,255,255,0.12);
}
.vb-storage-twentyone-columns {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-twentyone-columns section {
display: grid;
align-content: start;
gap: 12px;
min-height: 390px;
padding: 14px;
border-radius: 26px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
}
.vb-storage-twentyone-columns h4 {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 20px !important;
line-height: 1.15 !important;
font-weight: 950 !important;
}
.vb-storage-twentyone-columns h4 span {
display: grid;
place-items: center;
min-width: 34px;
height: 34px;
border-radius: 999px;
background: #e0f2fe;
color: #0369a1 !important;
-webkit-text-fill-color: #0369a1 !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-twentyone-columns [data-task-column] {
display: grid;
gap: 10px;
}
.vb-storage-twentyone-task {
display: grid;
gap: 10px;
padding: 13px;
border-radius: 18px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.24);
box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
}
.vb-storage-twentyone-task strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
line-height: 1.35;
font-weight: 850;
overflow-wrap: anywhere;
}
.vb-storage-twentyone-actions {
display: flex;
gap: 7px;
flex-wrap: wrap;
}
.vb-storage-twentyone-actions button {
min-height: 32px;
padding: 6px 9px;
border: 0;
border-radius: 999px;
background: #e0e7ff;
color: #3730a3 !important;
-webkit-text-fill-color: #3730a3 !important;
font-size: 11px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyone-actions button:last-child {
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
@media (max-width: 940px) {
.vb-storage-twentyone-columns {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-twentyone-form {
grid-template-columns: 1fr;
}
.vb-storage-twentyone-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This Kanban board localStorage example is useful for task managers, project dashboards, content planning boards, CRM pipeline demos, productivity apps, and JavaScript portfolio projects that need persistent grouped data.
A shopping cart saved with localStorage is one of the most practical JavaScript localStorage examples for ecommerce websites, product landing pages, digital product shops, affiliate demos, and cart UI prototypes. It lets visitors add products to a cart and keep the cart after refresh.
This example lets users add products, increase or decrease quantity, remove items, clear the cart, and restore the cart from localStorage after page reload. JavaScript stores the cart as a JSON array and recalculates the total every time the cart changes.
Add products to the cart, refresh the page, and localStorage restores the full cart with quantities.
Responsive landing page template for a modern website.
49€Small browser feature that saves user actions locally.
29€Technical SEO review for structure, speed, and content.
99€(function () {
const wrapper = document.querySelector("[data-vb-storage-twentytwo]");
if (!wrapper) return;
const storageKey = "vbStorageTwentytwoCart";
const products = wrapper.querySelectorAll("[data-product-id]");
const cartList = wrapper.querySelector("[data-cart-list]");
const cartCount = wrapper.querySelector("[data-cart-count]");
const cartTotal = wrapper.querySelector("[data-cart-total]");
const clearButton = wrapper.querySelector("[data-clear-cart]");
let cart = [];
function saveCart() {
localStorage.setItem(storageKey, JSON.stringify(cart));
}
function loadCart() {
const savedCart = localStorage.getItem(storageKey);
if (!savedCart) return;
try {
const parsedCart = JSON.parse(savedCart);
cart = Array.isArray(parsedCart) ? parsedCart : [];
} catch (error) {
cart = [];
localStorage.removeItem(storageKey);
}
}
function renderCart() {
cartList.innerHTML = "";
const totalItems = cart.reduce(function (sum, item) {
return sum + item.quantity;
}, 0);
const subtotal = cart.reduce(function (sum, item) {
return sum + item.price * item.quantity;
}, 0);
cartCount.textContent = totalItems === 1 ? "1 item" : totalItems + " items";
cartTotal.textContent = subtotal + "€";
if (cart.length === 0) {
cartList.innerHTML = '<p class="vb-storage-twentytwo-empty">Your cart is empty.</p>';
saveCart();
return;
}
cart.forEach(function (item) {
const row = document.createElement("div");
row.className = "vb-storage-twentytwo-cart-item";
row.innerHTML =
'<div class="vb-storage-twentytwo-cart-item-top">' +
'<strong>' + item.name + '</strong>' +
'<span>' + item.price + '€</span>' +
'</div>' +
'<div class="vb-storage-twentytwo-qty">' +
'<button type="button" data-decrease="' + item.id + '">−</button>' +
'<small>Qty ' + item.quantity + '</small>' +
'<button type="button" data-increase="' + item.id + '">+</button>' +
'<button type="button" data-remove="' + item.id + '">×</button>' +
'</div>';
cartList.appendChild(row);
});
saveCart();
}
function addToCart(product) {
const productId = product.getAttribute("data-product-id");
const existingItem = cart.find(function (item) {
return item.id === productId;
});
if (existingItem) {
existingItem.quantity += 1;
} else {
cart.push({
id: productId,
name: product.getAttribute("data-product-name"),
price: Number(product.getAttribute("data-product-price")),
quantity: 1
});
}
renderCart();
}
function changeQuantity(productId, amount) {
cart = cart.map(function (item) {
if (item.id === productId) {
item.quantity += amount;
}
return item;
}).filter(function (item) {
return item.quantity > 0;
});
renderCart();
}
function removeItem(productId) {
cart = cart.filter(function (item) {
return item.id !== productId;
});
renderCart();
}
products.forEach(function (product) {
product.querySelector("[data-add-cart]").addEventListener("click", function () {
addToCart(product);
});
});
cartList.addEventListener("click", function (event) {
const increaseId = event.target.getAttribute("data-increase");
const decreaseId = event.target.getAttribute("data-decrease");
const removeId = event.target.getAttribute("data-remove");
if (increaseId) changeQuantity(increaseId, 1);
if (decreaseId) changeQuantity(decreaseId, -1);
if (removeId) removeItem(removeId);
});
clearButton.addEventListener("click", function () {
cart = [];
localStorage.removeItem(storageKey);
renderCart();
});
loadCart();
renderCart();
})();
<div class="vb-storage-twentytwo-demo">
<div class="vb-storage-twentytwo-shop" data-vb-storage-twentytwo>
<div class="vb-storage-twentytwo-head">
<span class="vb-storage-twentytwo-kicker">Example 22</span>
<h3>Saved Shopping Cart</h3>
<p>Add products to the cart, refresh the page, and localStorage restores the full cart with quantities.</p>
</div>
<div class="vb-storage-twentytwo-layout">
<div class="vb-storage-twentytwo-products">
<article data-product-id="template" data-product-name="Website Template" data-product-price="49">
<span>WEB</span>
<h4>Website Template</h4>
<p>Responsive landing page template for a modern website.</p>
<strong>49€</strong>
<button type="button" data-add-cart>Add to Cart</button>
</article>
<article data-product-id="plugin" data-product-name="JavaScript Plugin" data-product-price="29">
<span>JS</span>
<h4>JavaScript Plugin</h4>
<p>Small browser feature that saves user actions locally.</p>
<strong>29€</strong>
<button type="button" data-add-cart>Add to Cart</button>
</article>
<article data-product-id="audit" data-product-name="SEO Audit" data-product-price="99">
<span>SEO</span>
<h4>SEO Audit</h4>
<p>Technical SEO review for structure, speed, and content.</p>
<strong>99€</strong>
<button type="button" data-add-cart>Add to Cart</button>
</article>
</div>
<aside class="vb-storage-twentytwo-cart">
<div class="vb-storage-twentytwo-cart-head">
<strong>Your Cart</strong>
<span data-cart-count>0 items</span>
</div>
<div class="vb-storage-twentytwo-cart-list" data-cart-list>
<p class="vb-storage-twentytwo-empty">Your cart is empty.</p>
</div>
<div class="vb-storage-twentytwo-total">
<span>Subtotal</span>
<strong data-cart-total>0€</strong>
</div>
<button type="button" data-clear-cart>Clear Cart</button>
</aside>
</div>
</div>
</div>
.vb-storage-twentytwo-demo,
.vb-storage-twentytwo-demo * {
box-sizing: border-box;
}
.vb-storage-twentytwo-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.16), transparent 34%),
linear-gradient(135deg, #ecfdf5 0%, #eff6ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(16, 185, 129, 0.18);
box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}
.vb-storage-twentytwo-shop {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentytwo-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-twentytwo-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #dcfce7;
color: #15803d !important;
-webkit-text-fill-color: #15803d !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentytwo-head h3 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentytwo-head p {
max-width: 780px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentytwo-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(320px, 410px);
gap: 20px;
align-items: start;
}
.vb-storage-twentytwo-products {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-twentytwo-products article {
display: grid;
align-content: start;
gap: 11px;
min-height: 280px;
padding: 18px;
border-radius: 26px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.24);
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}
.vb-storage-twentytwo-products article > span {
display: grid;
place-items: center;
width: 64px;
height: 64px;
border-radius: 22px;
background: linear-gradient(135deg, #10b981, #2563eb);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 16px;
font-weight: 950;
}
.vb-storage-twentytwo-products h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 22px !important;
line-height: 1.12 !important;
font-weight: 950 !important;
}
.vb-storage-twentytwo-products p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
}
.vb-storage-twentytwo-products strong {
margin-top: auto;
color: #059669 !important;
-webkit-text-fill-color: #059669 !important;
font-size: 26px;
line-height: 1;
font-weight: 950;
}
.vb-storage-twentytwo-products button,
.vb-storage-twentytwo-cart > button {
min-height: 44px;
border: 0;
border-radius: 999px;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentytwo-products button {
background: linear-gradient(135deg, #10b981, #2563eb);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-twentytwo-cart {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #0f172a;
box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}
.vb-storage-twentytwo-cart-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-twentytwo-cart-head strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-twentytwo-cart-head span {
color: #a7f3d0 !important;
-webkit-text-fill-color: #a7f3d0 !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-twentytwo-cart-list {
display: grid;
gap: 10px;
min-height: 280px;
}
.vb-storage-twentytwo-empty {
display: grid;
place-items: center;
min-height: 280px;
margin: 0 !important;
border: 1px dashed rgba(255,255,255,0.22);
border-radius: 20px;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-twentytwo-cart-item {
display: grid;
gap: 10px;
padding: 12px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentytwo-cart-item-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.vb-storage-twentytwo-cart-item strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
line-height: 1.25;
font-weight: 900;
}
.vb-storage-twentytwo-cart-item span {
color: #a7f3d0 !important;
-webkit-text-fill-color: #a7f3d0 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-twentytwo-qty {
display: flex;
align-items: center;
gap: 7px;
}
.vb-storage-twentytwo-qty button {
width: 32px;
height: 32px;
border: 0;
border-radius: 999px;
background: rgba(255,255,255,0.12);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 15px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentytwo-qty small {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-twentytwo-total {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
padding: 16px;
border-radius: 20px;
background: rgba(255,255,255,0.10);
}
.vb-storage-twentytwo-total span {
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 900;
}
.vb-storage-twentytwo-total strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 34px;
line-height: 1;
font-weight: 950;
}
.vb-storage-twentytwo-cart > button {
background: #ffffff;
color: #047857 !important;
-webkit-text-fill-color: #047857 !important;
}
@media (max-width: 980px) {
.vb-storage-twentytwo-layout {
grid-template-columns: 1fr;
}
.vb-storage-twentytwo-products {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.vb-storage-twentytwo-products {
grid-template-columns: 1fr;
}
.vb-storage-twentytwo-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This shopping cart localStorage example is useful for ecommerce demos, WooCommerce-style product pages, digital product shops, checkout prototypes, mini cart features, and JavaScript portfolio projects.
Form autosave with localStorage is useful for contact forms, quote request forms, application forms, booking forms, support tickets, long surveys, and checkout flows. It prevents users from losing typed content if they accidentally refresh the page.
This example automatically saves form fields while the user types. JavaScript restores the draft from localStorage after refresh, shows a saved status message, and lets the user clear the saved draft when needed.
Type into the form and refresh the page. localStorage restores the saved draft automatically.
(function () {
const wrapper = document.querySelector("[data-vb-storage-twentythree]");
if (!wrapper) return;
const storageKey = "vbStorageTwentythreeFormDraft";
const form = wrapper.querySelector("[data-autosave-form]");
const fields = Array.from(form.querySelectorAll("input, select, textarea"));
const status = wrapper.querySelector("[data-draft-status]");
const clearButton = wrapper.querySelector("[data-clear-draft]");
let saveTimer;
function getDraftData() {
const data = {};
fields.forEach(function (field) {
data[field.name] = field.value;
});
return data;
}
function saveDraft() {
localStorage.setItem(storageKey, JSON.stringify(getDraftData()));
status.textContent = "Draft status: saved at " + new Date().toLocaleTimeString();
}
function loadDraft() {
const savedDraft = localStorage.getItem(storageKey);
if (!savedDraft) return;
try {
const data = JSON.parse(savedDraft);
fields.forEach(function (field) {
field.value = data[field.name] || "";
});
status.textContent = "Draft status: restored from localStorage.";
} catch (error) {
localStorage.removeItem(storageKey);
status.textContent = "Draft status: saved draft could not be loaded.";
}
}
function scheduleSave() {
status.textContent = "Draft status: saving...";
clearTimeout(saveTimer);
saveTimer = setTimeout(saveDraft, 350);
}
fields.forEach(function (field) {
field.addEventListener("input", scheduleSave);
field.addEventListener("change", scheduleSave);
});
form.addEventListener("submit", function (event) {
event.preventDefault();
localStorage.removeItem(storageKey);
status.textContent = "Demo submitted. Saved draft has been cleared.";
form.reset();
});
clearButton.addEventListener("click", function () {
localStorage.removeItem(storageKey);
form.reset();
status.textContent = "Draft status: cleared.";
});
loadDraft();
})();
<div class="vb-storage-twentythree-demo">
<div class="vb-storage-twentythree-formwrap" data-vb-storage-twentythree>
<div class="vb-storage-twentythree-intro">
<span class="vb-storage-twentythree-kicker">Example 23</span>
<h3>Form Autosave Draft</h3>
<p>Type into the form and refresh the page. localStorage restores the saved draft automatically.</p>
<div class="vb-storage-twentythree-status" data-draft-status>
Draft status: ready.
</div>
</div>
<form class="vb-storage-twentythree-form" data-autosave-form>
<label>
<span>Your name</span>
<input type="text" name="name" placeholder="Your name">
</label>
<label>
<span>Email address</span>
<input type="email" name="email" placeholder="you@example.com">
</label>
<label>
<span>Project type</span>
<select name="projectType">
<option value="">Choose project type</option>
<option value="Website">Website</option>
<option value="Ecommerce">Ecommerce</option>
<option value="WordPress Plugin">WordPress Plugin</option>
<option value="JavaScript Feature">JavaScript Feature</option>
</select>
</label>
<label>
<span>Project message</span>
<textarea name="message" rows="6" placeholder="Describe what you need..."></textarea>
</label>
<div class="vb-storage-twentythree-actions">
<button type="submit">Submit Demo</button>
<button type="button" data-clear-draft>Clear Saved Draft</button>
</div>
</form>
</div>
</div>
.vb-storage-twentythree-demo,
.vb-storage-twentythree-demo * {
box-sizing: border-box;
}
.vb-storage-twentythree-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(236, 72, 153, 0.15), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
linear-gradient(135deg, #fdf2f8 0%, #eef2ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(236, 72, 153, 0.18);
box-shadow: 0 28px 80px rgba(157, 23, 77, 0.10);
}
.vb-storage-twentythree-formwrap {
display: grid;
grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentythree-intro,
.vb-storage-twentythree-form {
min-width: 0;
}
.vb-storage-twentythree-intro {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #111827;
}
.vb-storage-twentythree-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(236, 72, 153, 0.16);
color: #fbcfe8 !important;
-webkit-text-fill-color: #fbcfe8 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentythree-intro h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentythree-intro p {
max-width: 560px;
margin: 0 0 22px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentythree-status {
padding: 13px 15px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
color: #fbcfe8 !important;
-webkit-text-fill-color: #fbcfe8 !important;
font-size: 14px;
line-height: 1.45;
font-weight: 850;
}
.vb-storage-twentythree-form {
display: grid;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-twentythree-form label {
display: grid;
gap: 7px;
}
.vb-storage-twentythree-form label span {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-twentythree-form input,
.vb-storage-twentythree-form select,
.vb-storage-twentythree-form textarea {
width: 100%;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #ffffff;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
font-weight: 700;
outline: none;
}
.vb-storage-twentythree-form input,
.vb-storage-twentythree-form select {
min-height: 50px;
padding: 0 15px;
}
.vb-storage-twentythree-form textarea {
resize: vertical;
padding: 14px 15px;
line-height: 1.55;
}
.vb-storage-twentythree-form input:focus,
.vb-storage-twentythree-form select:focus,
.vb-storage-twentythree-form textarea:focus {
border-color: rgba(236, 72, 153, 0.70);
box-shadow: 0 0 0 4px rgba(236, 72, 153, 0.10);
}
.vb-storage-twentythree-actions {
display: grid;
grid-template-columns: 1fr auto;
gap: 10px;
}
.vb-storage-twentythree-actions button {
min-height: 48px;
padding: 0 16px;
border: 0;
border-radius: 999px;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentythree-actions button:first-child {
background: linear-gradient(135deg, #ec4899, #6366f1);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-twentythree-actions button:last-child {
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
@media (max-width: 900px) {
.vb-storage-twentythree-formwrap {
grid-template-columns: 1fr;
}
}
@media (max-width: 580px) {
.vb-storage-twentythree-actions {
grid-template-columns: 1fr;
}
.vb-storage-twentythree-intro h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This form autosave localStorage example is useful for contact forms, quote request forms, application forms, checkout forms, booking forms, support tickets, survey forms, and long lead generation forms.
Saving dark mode with localStorage is one of the most searched JavaScript localStorage examples. It is useful for blogs, dashboards, documentation websites, SaaS interfaces, portfolios, admin panels, and modern landing pages.
This example toggles between light mode and dark mode. JavaScript saves the selected theme in localStorage, applies the theme instantly with a data attribute, and restores the same theme after refresh.
Switch between light and dark mode. localStorage remembers your selected theme after refresh.
This preview changes between light and dark mode using one saved localStorage value.
(function () {
const wrapper = document.querySelector("[data-vb-storage-twentyfour]");
if (!wrapper) return;
const storageKey = "vbStorageTwentyfourTheme";
const toggleButton = wrapper.querySelector("[data-theme-toggle]");
const status = wrapper.querySelector("[data-theme-status]");
function applyTheme(theme) {
wrapper.setAttribute("data-theme", theme);
localStorage.setItem(storageKey, theme);
status.textContent = "Current theme: " + theme;
toggleButton.textContent = theme === "dark" ? "Switch to Light Mode" : "Switch to Dark Mode";
}
toggleButton.addEventListener("click", function () {
const currentTheme = wrapper.getAttribute("data-theme");
applyTheme(currentTheme === "dark" ? "light" : "dark");
});
applyTheme(localStorage.getItem(storageKey) || "light");
})();
<div class="vb-storage-twentyfour-demo">
<div class="vb-storage-twentyfour-theme" data-vb-storage-twentyfour data-theme="light">
<div class="vb-storage-twentyfour-panel">
<span class="vb-storage-twentyfour-kicker">Example 24</span>
<h3>Saved Dark Mode Theme</h3>
<p>Switch between light and dark mode. localStorage remembers your selected theme after refresh.</p>
<button type="button" data-theme-toggle>
Toggle Dark Mode
</button>
<div class="vb-storage-twentyfour-status" data-theme-status>
Current theme: light
</div>
</div>
<div class="vb-storage-twentyfour-preview">
<div class="vb-storage-twentyfour-window">
<div class="vb-storage-twentyfour-window-top">
<span></span>
<span></span>
<span></span>
</div>
<div class="vb-storage-twentyfour-content">
<strong>Theme Preview</strong>
<p>This preview changes between light and dark mode using one saved localStorage value.</p>
<div class="vb-storage-twentyfour-cards">
<div>
<span>Readability</span>
<strong>High</strong>
</div>
<div>
<span>Saved</span>
<strong>Yes</strong>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
.vb-storage-twentyfour-demo,
.vb-storage-twentyfour-demo * {
box-sizing: border-box;
}
.vb-storage-twentyfour-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(15, 23, 42, 0.14), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
linear-gradient(135deg, #f8fafc 0%, #eef2ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(15, 23, 42, 0.12);
box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentyfour-theme {
display: grid;
grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
transition: background 0.25s ease, border-color 0.25s ease;
}
.vb-storage-twentyfour-theme[data-theme="dark"] {
background: #020617;
border-color: rgba(255,255,255,0.10);
}
.vb-storage-twentyfour-panel,
.vb-storage-twentyfour-preview {
min-width: 0;
}
.vb-storage-twentyfour-panel {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #0f172a;
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-panel {
background: #111827;
border: 1px solid rgba(255,255,255,0.10);
}
.vb-storage-twentyfour-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(129, 140, 248, 0.18);
color: #c7d2fe !important;
-webkit-text-fill-color: #c7d2fe !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentyfour-panel h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentyfour-panel p {
max-width: 560px;
margin: 0 0 22px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentyfour-panel button {
align-self: flex-start;
min-height: 50px;
padding: 0 18px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #6366f1, #0ea5e9);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyfour-status {
align-self: flex-start;
margin-top: 14px;
padding: 12px 14px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
color: #e0e7ff !important;
-webkit-text-fill-color: #e0e7ff !important;
font-size: 14px;
font-weight: 850;
}
.vb-storage-twentyfour-preview {
display: grid;
place-items: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
transition: background 0.25s ease, border-color 0.25s ease;
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-preview {
background: #0f172a;
border-color: rgba(255,255,255,0.10);
}
.vb-storage-twentyfour-window {
width: 100%;
max-width: 560px;
overflow: hidden;
border-radius: 28px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 22px 60px rgba(15, 23, 42, 0.12);
transition: background 0.25s ease, border-color 0.25s ease;
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-window {
background: #020617;
border-color: rgba(255,255,255,0.12);
}
.vb-storage-twentyfour-window-top {
display: flex;
gap: 8px;
padding: 16px;
background: #f1f5f9;
border-bottom: 1px solid rgba(148, 163, 184, 0.22);
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-window-top {
background: #111827;
border-bottom-color: rgba(255,255,255,0.10);
}
.vb-storage-twentyfour-window-top span {
width: 12px;
height: 12px;
border-radius: 999px;
background: #f87171;
}
.vb-storage-twentyfour-window-top span:nth-child(2) {
background: #fbbf24;
}
.vb-storage-twentyfour-window-top span:nth-child(3) {
background: #34d399;
}
.vb-storage-twentyfour-content {
display: grid;
gap: 16px;
padding: clamp(24px, 5vw, 46px);
}
.vb-storage-twentyfour-content > strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(34px, 5vw, 54px);
line-height: 0.96;
font-weight: 950;
letter-spacing: -0.07em;
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-content > strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-twentyfour-content p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-content p {
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
}
.vb-storage-twentyfour-cards {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.vb-storage-twentyfour-cards div {
padding: 16px;
border-radius: 20px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-cards div {
background: #111827;
border-color: rgba(255,255,255,0.10);
}
.vb-storage-twentyfour-cards span {
display: block;
margin-bottom: 7px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-cards span {
color: #94a3b8 !important;
-webkit-text-fill-color: #94a3b8 !important;
}
.vb-storage-twentyfour-cards strong {
color: #4f46e5 !important;
-webkit-text-fill-color: #4f46e5 !important;
font-size: 22px;
font-weight: 950;
}
@media (max-width: 900px) {
.vb-storage-twentyfour-theme {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.vb-storage-twentyfour-panel h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
.vb-storage-twentyfour-panel button {
width: 100%;
}
.vb-storage-twentyfour-cards {
grid-template-columns: 1fr;
}
}
This dark mode localStorage example is useful for blogs, dashboards, SaaS interfaces, documentation websites, admin panels, user portals, portfolio websites, and modern JavaScript UI preference features.
If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.
Recent searches saved with localStorage are useful for search bars, ecommerce stores, documentation websites, blog search pages, SaaS dashboards, help centers, and directory websites. It helps users quickly repeat previous searches without needing a backend account system.
This example saves submitted search terms into localStorage, displays the latest searches as clickable chips, restores them after refresh, and allows users to remove individual searches or clear the full history.
Search for something, refresh the page, and localStorage keeps your recent search history.
No recent searches saved yet.
(function () {
const wrapper = document.querySelector("[data-vb-storage-twentyfive]");
if (!wrapper) return;
const storageKey = "vbStorageTwentyfiveRecentSearches";
const form = wrapper.querySelector("[data-search-form]");
const input = wrapper.querySelector("[data-search-input]");
const searchList = wrapper.querySelector("[data-search-list]");
const currentSearch = wrapper.querySelector("[data-current-search]");
const clearButton = wrapper.querySelector("[data-clear-searches]");
let searches = [];
function saveSearches() {
localStorage.setItem(storageKey, JSON.stringify(searches));
}
function loadSearches() {
const savedSearches = localStorage.getItem(storageKey);
if (!savedSearches) return;
try {
const parsedSearches = JSON.parse(savedSearches);
searches = Array.isArray(parsedSearches) ? parsedSearches : [];
} catch (error) {
searches = [];
localStorage.removeItem(storageKey);
}
}
function renderSearches() {
searchList.innerHTML = "";
if (searches.length === 0) {
searchList.innerHTML = '<p class="vb-storage-twentyfive-empty">No recent searches saved yet.</p>';
return;
}
searches.forEach(function (term) {
const chip = document.createElement("div");
chip.className = "vb-storage-twentyfive-chip";
chip.innerHTML =
'<button type="button" data-use-search="' + term + '">' + term + '</button>' +
'<button type="button" data-remove-search="' + term + '">×</button>';
searchList.appendChild(chip);
});
}
function addSearch(term) {
const cleanTerm = term.trim();
if (!cleanTerm) return;
searches = searches.filter(function (item) {
return item.toLowerCase() !== cleanTerm.toLowerCase();
});
searches.unshift(cleanTerm);
searches = searches.slice(0, 8);
currentSearch.textContent = cleanTerm;
input.value = cleanTerm;
saveSearches();
renderSearches();
}
form.addEventListener("submit", function (event) {
event.preventDefault();
addSearch(input.value);
});
searchList.addEventListener("click", function (event) {
const useSearch = event.target.getAttribute("data-use-search");
const removeSearch = event.target.getAttribute("data-remove-search");
if (useSearch) {
currentSearch.textContent = useSearch;
input.value = useSearch;
}
if (removeSearch) {
searches = searches.filter(function (item) {
return item !== removeSearch;
});
saveSearches();
renderSearches();
}
});
clearButton.addEventListener("click", function () {
searches = [];
localStorage.removeItem(storageKey);
currentSearch.textContent = "No search yet";
input.value = "";
renderSearches();
});
loadSearches();
renderSearches();
})();
<div class="vb-storage-twentyfive-demo">
<div class="vb-storage-twentyfive-search" data-vb-storage-twentyfive>
<div class="vb-storage-twentyfive-head">
<span class="vb-storage-twentyfive-kicker">Example 25</span>
<h3>Saved Recent Searches</h3>
<p>Search for something, refresh the page, and localStorage keeps your recent search history.</p>
</div>
<form class="vb-storage-twentyfive-form" data-search-form>
<input type="search" data-search-input placeholder="Search tutorials, products, docs...">
<button type="submit">Search</button>
</form>
<div class="vb-storage-twentyfive-current">
<span>Current search</span>
<strong data-current-search>No search yet</strong>
</div>
<div class="vb-storage-twentyfive-history">
<div class="vb-storage-twentyfive-history-head">
<strong>Recent Searches</strong>
<button type="button" data-clear-searches>Clear All</button>
</div>
<div class="vb-storage-twentyfive-list" data-search-list>
<p class="vb-storage-twentyfive-empty">No recent searches saved yet.</p>
</div>
</div>
</div>
</div>
.vb-storage-twentyfive-demo,
.vb-storage-twentyfive-demo * {
box-sizing: border-box;
}
.vb-storage-twentyfive-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.14), transparent 34%),
linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 56%, #ffffff 100%) !important;
border: 1px solid rgba(14, 165, 233, 0.18);
box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}
.vb-storage-twentyfive-search {
max-width: 980px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #0f172a;
box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}
.vb-storage-twentyfive-head {
display: grid;
gap: 12px;
margin-bottom: 22px;
}
.vb-storage-twentyfive-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(14, 165, 233, 0.16);
color: #bae6fd !important;
-webkit-text-fill-color: #bae6fd !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentyfive-head h3 {
max-width: 780px;
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentyfive-head p {
max-width: 760px;
margin: 0 !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentyfive-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
margin-bottom: 16px;
padding: 14px;
border-radius: 24px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentyfive-form input {
min-width: 0;
min-height: 52px;
padding: 0 16px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 999px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 15px;
font-weight: 750;
outline: none;
}
.vb-storage-twentyfive-form input::placeholder {
color: #9ca3af;
-webkit-text-fill-color: #9ca3af;
}
.vb-storage-twentyfive-form input:focus {
border-color: rgba(14, 165, 233, 0.72);
box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.12);
}
.vb-storage-twentyfive-form button {
min-height: 52px;
padding: 0 18px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #0ea5e9, #22c55e);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyfive-current {
display: flex;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
margin-bottom: 16px;
padding: 15px;
border-radius: 20px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentyfive-current span {
color: #bae6fd !important;
-webkit-text-fill-color: #bae6fd !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-twentyfive-current strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
font-weight: 950;
}
.vb-storage-twentyfive-history {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #ffffff;
}
.vb-storage-twentyfive-history-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.vb-storage-twentyfive-history-head strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-twentyfive-history-head button {
min-height: 38px;
padding: 0 13px;
border: 0;
border-radius: 999px;
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
font-size: 12px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyfive-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
min-height: 150px;
align-content: flex-start;
}
.vb-storage-twentyfive-empty {
display: grid;
place-items: center;
width: 100%;
min-height: 150px;
margin: 0 !important;
border: 1px dashed rgba(148, 163, 184, 0.55);
border-radius: 20px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-twentyfive-chip {
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 42px;
padding: 8px 10px 8px 14px;
border-radius: 999px;
background: #f0f9ff;
border: 1px solid rgba(14, 165, 233, 0.20);
}
.vb-storage-twentyfive-chip button:first-child {
border: 0;
background: transparent;
color: #0369a1 !important;
-webkit-text-fill-color: #0369a1 !important;
font-size: 13px;
font-weight: 900;
cursor: pointer;
}
.vb-storage-twentyfive-chip button:last-child {
display: grid;
place-items: center;
width: 26px;
height: 26px;
border: 0;
border-radius: 999px;
background: #e0f2fe;
color: #0369a1 !important;
-webkit-text-fill-color: #0369a1 !important;
font-size: 14px;
font-weight: 950;
cursor: pointer;
}
@media (max-width: 640px) {
.vb-storage-twentyfive-form {
grid-template-columns: 1fr;
}
.vb-storage-twentyfive-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This recent searches localStorage example is useful for ecommerce search bars, blog search pages, documentation websites, SaaS dashboards, help centers, directory websites, and product finder interfaces.
Recently viewed products saved with localStorage are useful for ecommerce stores, WooCommerce product pages, affiliate websites, marketplaces, real estate listings, booking platforms, and product recommendation sections. It helps visitors return to items they already explored.
This example lets users click product cards to mark them as viewed. JavaScript saves recently viewed products in localStorage, displays them in a separate panel, avoids duplicates, and restores the same list after refresh.
Click product cards to add them to the viewed list. Refresh the page and your viewed products stay saved.
Fast hosting package for business websites.
29€Technical review for rankings and structure.
99€WordPress plugin built for custom workflows.
399€Modern responsive sales page section.
249€(function () {
const wrapper = document.querySelector("[data-vb-storage-twentysix]");
if (!wrapper) return;
const storageKey = "vbStorageTwentysixViewedProducts";
const products = Array.from(wrapper.querySelectorAll("[data-product]"));
const viewedList = wrapper.querySelector("[data-viewed-list]");
const clearButton = wrapper.querySelector("[data-clear-viewed]");
let viewedProducts = [];
function saveViewedProducts() {
localStorage.setItem(storageKey, JSON.stringify(viewedProducts));
}
function loadViewedProducts() {
const savedProducts = localStorage.getItem(storageKey);
if (!savedProducts) return;
try {
const parsedProducts = JSON.parse(savedProducts);
viewedProducts = Array.isArray(parsedProducts) ? parsedProducts : [];
} catch (error) {
viewedProducts = [];
localStorage.removeItem(storageKey);
}
}
function getProductData(product) {
return {
id: product.getAttribute("data-id"),
name: product.getAttribute("data-name"),
price: product.getAttribute("data-price"),
icon: product.getAttribute("data-icon")
};
}
function renderViewedProducts() {
viewedList.innerHTML = "";
products.forEach(function (product) {
const productId = product.getAttribute("data-id");
const isViewed = viewedProducts.some(function (item) {
return item.id === productId;
});
product.classList.toggle("is-viewed", isViewed);
});
if (viewedProducts.length === 0) {
viewedList.innerHTML = '<p class="vb-storage-twentysix-empty">No viewed products yet.</p>';
return;
}
viewedProducts.forEach(function (product) {
const item = document.createElement("div");
item.className = "vb-storage-twentysix-viewed";
item.innerHTML =
'<span>' + product.icon + '</span>' +
'<div>' +
'<strong>' + product.name + '</strong>' +
'<small>' + product.price + '</small>' +
'</div>';
viewedList.appendChild(item);
});
}
function addViewedProduct(product) {
const productData = getProductData(product);
viewedProducts = viewedProducts.filter(function (item) {
return item.id !== productData.id;
});
viewedProducts.unshift(productData);
viewedProducts = viewedProducts.slice(0, 5);
saveViewedProducts();
renderViewedProducts();
}
products.forEach(function (product) {
product.querySelector("[data-view-product]").addEventListener("click", function () {
addViewedProduct(product);
});
});
clearButton.addEventListener("click", function () {
viewedProducts = [];
localStorage.removeItem(storageKey);
renderViewedProducts();
});
loadViewedProducts();
renderViewedProducts();
})();
<div class="vb-storage-twentysix-demo">
<div class="vb-storage-twentysix-wrap" data-vb-storage-twentysix>
<div class="vb-storage-twentysix-head">
<span class="vb-storage-twentysix-kicker">Example 26</span>
<h3>Recently Viewed Products</h3>
<p>Click product cards to add them to the viewed list. Refresh the page and your viewed products stay saved.</p>
</div>
<div class="vb-storage-twentysix-layout">
<div class="vb-storage-twentysix-products">
<article data-product data-id="hosting" data-name="Cloud Hosting" data-price="29€" data-icon="CH">
<span>CH</span>
<h4>Cloud Hosting</h4>
<p>Fast hosting package for business websites.</p>
<strong>29€</strong>
<button type="button" data-view-product>View Product</button>
</article>
<article data-product data-id="audit" data-name="SEO Audit" data-price="99€" data-icon="SEO">
<span>SEO</span>
<h4>SEO Audit</h4>
<p>Technical review for rankings and structure.</p>
<strong>99€</strong>
<button type="button" data-view-product>View Product</button>
</article>
<article data-product data-id="plugin" data-name="Custom Plugin" data-price="399€" data-icon="WP">
<span>WP</span>
<h4>Custom Plugin</h4>
<p>WordPress plugin built for custom workflows.</p>
<strong>399€</strong>
<button type="button" data-view-product>View Product</button>
</article>
<article data-product data-id="landing" data-name="Landing Page" data-price="249€" data-icon="UI">
<span>UI</span>
<h4>Landing Page</h4>
<p>Modern responsive sales page section.</p>
<strong>249€</strong>
<button type="button" data-view-product>View Product</button>
</article>
</div>
<aside class="vb-storage-twentysix-panel">
<div class="vb-storage-twentysix-panel-head">
<strong>Viewed Products</strong>
<button type="button" data-clear-viewed>Clear</button>
</div>
<div class="vb-storage-twentysix-list" data-viewed-list>
<p class="vb-storage-twentysix-empty">No viewed products yet.</p>
</div>
</aside>
</div>
</div>
</div>
.vb-storage-twentysix-demo,
.vb-storage-twentysix-demo * {
box-sizing: border-box;
}
.vb-storage-twentysix-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.14), transparent 34%),
linear-gradient(135deg, #faf5ff 0%, #fdf2f8 56%, #ffffff 100%) !important;
border: 1px solid rgba(168, 85, 247, 0.18);
box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}
.vb-storage-twentysix-wrap {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentysix-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-twentysix-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #f3e8ff;
color: #7e22ce !important;
-webkit-text-fill-color: #7e22ce !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentysix-head h3 {
max-width: 820px;
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentysix-head p {
max-width: 780px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentysix-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(320px, 390px);
gap: 20px;
align-items: start;
}
.vb-storage-twentysix-products {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-twentysix-products article {
display: grid;
align-content: start;
gap: 11px;
min-height: 260px;
padding: 18px;
border-radius: 26px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.24);
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}
.vb-storage-twentysix-products article.is-viewed {
border-color: rgba(168, 85, 247, 0.55);
background: linear-gradient(135deg, #faf5ff, #ffffff) !important;
}
.vb-storage-twentysix-products article > span {
display: grid;
place-items: center;
width: 66px;
height: 66px;
border-radius: 22px;
background: linear-gradient(135deg, #a855f7, #ec4899);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 16px;
font-weight: 950;
}
.vb-storage-twentysix-products h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 23px !important;
line-height: 1.12 !important;
font-weight: 950 !important;
}
.vb-storage-twentysix-products p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
}
.vb-storage-twentysix-products strong {
margin-top: auto;
color: #7e22ce !important;
-webkit-text-fill-color: #7e22ce !important;
font-size: 26px;
line-height: 1;
font-weight: 950;
}
.vb-storage-twentysix-products button {
min-height: 44px;
border: 0;
border-radius: 999px;
background: linear-gradient(135deg, #a855f7, #ec4899);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentysix-panel {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #111827;
box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}
.vb-storage-twentysix-panel-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-twentysix-panel-head strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-twentysix-panel-head button {
min-height: 38px;
padding: 0 13px;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #7e22ce !important;
-webkit-text-fill-color: #7e22ce !important;
font-size: 12px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentysix-list {
display: grid;
gap: 10px;
min-height: 320px;
}
.vb-storage-twentysix-empty {
display: grid;
place-items: center;
min-height: 320px;
margin: 0 !important;
border: 1px dashed rgba(255,255,255,0.22);
border-radius: 20px;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-twentysix-viewed {
display: grid;
grid-template-columns: 52px minmax(0, 1fr);
gap: 12px;
align-items: center;
padding: 12px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentysix-viewed span {
display: grid;
place-items: center;
width: 52px;
height: 52px;
border-radius: 16px;
background: linear-gradient(135deg, #a855f7, #ec4899);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-twentysix-viewed strong {
display: block;
margin-bottom: 4px;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
line-height: 1.25;
font-weight: 900;
}
.vb-storage-twentysix-viewed small {
color: #fbcfe8 !important;
-webkit-text-fill-color: #fbcfe8 !important;
font-size: 12px;
font-weight: 850;
}
@media (max-width: 940px) {
.vb-storage-twentysix-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-twentysix-products {
grid-template-columns: 1fr;
}
.vb-storage-twentysix-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This recently viewed products localStorage example is useful for ecommerce stores, WooCommerce layouts, product detail pages, affiliate product roundups, marketplace listings, booking pages, and product recommendation widgets.
Product filters saved with localStorage are useful for ecommerce category pages, real estate listings, job boards, directories, blog archives, product catalogs, and comparison websites. It keeps filter choices active after refresh, so users do not lose their selected view.
This example filters product cards by category, price range, and availability. JavaScript saves the selected filters in localStorage, restores them after refresh, and updates the visible product count instantly.
Modern responsive landing page section.
249€Custom WordPress quote request system.
399€Technical SEO and content review.
99€WooCommerce style product page setup.
499€Saved theme preference component.
89€SEO structure for long-form articles.
299€(function () {
const wrapper = document.querySelector("[data-vb-storage-twentyseven]");
if (!wrapper) return;
const storageKey = "vbStorageTwentysevenFilters";
const filterFields = wrapper.querySelectorAll("[data-filter]");
const productCards = Array.from(wrapper.querySelectorAll("[data-product-card]"));
const resultCount = wrapper.querySelector("[data-result-count]");
const resetButton = wrapper.querySelector("[data-reset-filters]");
const defaultFilters = {
category: "all",
price: "9999",
available: false
};
let filters = Object.assign({}, defaultFilters);
function saveFilters() {
localStorage.setItem(storageKey, JSON.stringify(filters));
}
function loadFilters() {
const savedFilters = localStorage.getItem(storageKey);
if (!savedFilters) return;
try {
filters = Object.assign({}, defaultFilters, JSON.parse(savedFilters));
} catch (error) {
filters = Object.assign({}, defaultFilters);
localStorage.removeItem(storageKey);
}
}
function syncFields() {
filterFields.forEach(function (field) {
const key = field.getAttribute("data-filter");
if (field.type === "checkbox") {
field.checked = Boolean(filters[key]);
} else {
field.value = filters[key];
}
});
}
function applyFilters() {
let visibleCount = 0;
productCards.forEach(function (card) {
const category = card.getAttribute("data-category");
const price = Number(card.getAttribute("data-price"));
const available = card.getAttribute("data-available") === "true";
const matchesCategory = filters.category === "all" || filters.category === category;
const matchesPrice = price <= Number(filters.price);
const matchesAvailability = !filters.available || available;
const isVisible = matchesCategory && matchesPrice && matchesAvailability;
card.classList.toggle("is-hidden", !isVisible);
if (isVisible) {
visibleCount += 1;
}
});
resultCount.textContent = visibleCount === 1 ? "1 product" : visibleCount + " products";
saveFilters();
}
filterFields.forEach(function (field) {
field.addEventListener("change", function () {
const key = field.getAttribute("data-filter");
filters[key] = field.type === "checkbox" ? field.checked : field.value;
applyFilters();
});
});
resetButton.addEventListener("click", function () {
filters = Object.assign({}, defaultFilters);
localStorage.removeItem(storageKey);
syncFields();
applyFilters();
});
loadFilters();
syncFields();
applyFilters();
})();
<div class="vb-storage-twentyseven-demo">
<div class="vb-storage-twentyseven-filter" data-vb-storage-twentyseven>
<aside class="vb-storage-twentyseven-sidebar">
<span class="vb-storage-twentyseven-kicker">Example 27</span>
<h3>Saved Product Filters</h3>
<p>Choose filters and refresh the page. localStorage restores the same product filter state.</p>
<label>
<span>Category</span>
<select data-filter="category">
<option value="all">All categories</option>
<option value="website">Website</option>
<option value="plugin">Plugin</option>
<option value="seo">SEO</option>
</select>
</label>
<label>
<span>Max price</span>
<select data-filter="price">
<option value="9999">Any price</option>
<option value="100">Up to 100€</option>
<option value="300">Up to 300€</option>
<option value="500">Up to 500€</option>
</select>
</label>
<label class="vb-storage-twentyseven-check">
<input type="checkbox" data-filter="available">
<span>Available only</span>
</label>
<button type="button" data-reset-filters>Reset Filters</button>
</aside>
<section class="vb-storage-twentyseven-results">
<div class="vb-storage-twentyseven-results-head">
<strong>Product Results</strong>
<span data-result-count>6 products</span>
</div>
<div class="vb-storage-twentyseven-grid">
<article data-product-card data-category="website" data-price="249" data-available="true">
<span>Website</span>
<h4>Landing Page</h4>
<p>Modern responsive landing page section.</p>
<strong>249€</strong>
</article>
<article data-product-card data-category="plugin" data-price="399" data-available="true">
<span>Plugin</span>
<h4>Quote Form Plugin</h4>
<p>Custom WordPress quote request system.</p>
<strong>399€</strong>
</article>
<article data-product-card data-category="seo" data-price="99" data-available="true">
<span>SEO</span>
<h4>SEO Audit</h4>
<p>Technical SEO and content review.</p>
<strong>99€</strong>
</article>
<article data-product-card data-category="website" data-price="499" data-available="false">
<span>Website</span>
<h4>Ecommerce Setup</h4>
<p>WooCommerce style product page setup.</p>
<strong>499€</strong>
</article>
<article data-product-card data-category="plugin" data-price="89" data-available="true">
<span>Plugin</span>
<h4>Dark Mode Widget</h4>
<p>Saved theme preference component.</p>
<strong>89€</strong>
</article>
<article data-product-card data-category="seo" data-price="299" data-available="false">
<span>SEO</span>
<h4>Content SEO Plan</h4>
<p>SEO structure for long-form articles.</p>
<strong>299€</strong>
</article>
</div>
</section>
</div>
</div>
.vb-storage-twentyseven-demo,
.vb-storage-twentyseven-demo * {
box-sizing: border-box;
}
.vb-storage-twentyseven-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.15), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #fffbeb 56%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-twentyseven-filter {
display: grid;
grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
gap: 22px;
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentyseven-sidebar,
.vb-storage-twentyseven-results {
min-width: 0;
}
.vb-storage-twentyseven-sidebar {
display: grid;
align-content: start;
gap: 13px;
padding: clamp(18px, 3vw, 24px);
border-radius: 28px;
background: #0f172a;
}
.vb-storage-twentyseven-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(245, 158, 11, 0.16);
color: #fde68a !important;
-webkit-text-fill-color: #fde68a !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentyseven-sidebar h3 {
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(34px, 5vw, 58px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.07em;
}
.vb-storage-twentyseven-sidebar p {
margin: 0 0 8px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 15px;
line-height: 1.65;
font-weight: 650;
}
.vb-storage-twentyseven-sidebar label {
display: grid;
gap: 7px;
}
.vb-storage-twentyseven-sidebar label span {
color: #e0f2fe !important;
-webkit-text-fill-color: #e0f2fe !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-twentyseven-sidebar select {
width: 100%;
min-height: 46px;
padding: 0 13px;
border: 1px solid rgba(255,255,255,0.14);
border-radius: 15px;
background: rgba(255,255,255,0.10);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
font-weight: 750;
outline: none;
}
.vb-storage-twentyseven-check {
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: 10px !important;
min-height: 46px;
padding: 10px 12px;
border-radius: 16px;
background: rgba(255,255,255,0.08);
}
.vb-storage-twentyseven-check input {
width: 18px;
height: 18px;
accent-color: #f59e0b;
}
.vb-storage-twentyseven-sidebar button {
min-height: 44px;
margin-top: 4px;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyseven-results {
display: grid;
gap: 16px;
padding: clamp(18px, 3vw, 24px);
border-radius: 28px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-twentyseven-results-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.vb-storage-twentyseven-results-head strong {
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-twentyseven-results-head span {
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-twentyseven-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
min-height: 480px;
}
.vb-storage-twentyseven-grid article {
display: grid;
align-content: start;
gap: 10px;
min-height: 210px;
padding: 16px;
border-radius: 22px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}
.vb-storage-twentyseven-grid article.is-hidden {
display: none;
}
.vb-storage-twentyseven-grid article span {
display: inline-flex;
justify-self: start;
padding: 7px 10px;
border-radius: 999px;
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 11px;
font-weight: 950;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-twentyseven-grid article h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 21px !important;
line-height: 1.12 !important;
font-weight: 950 !important;
}
.vb-storage-twentyseven-grid article p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
}
.vb-storage-twentyseven-grid article strong {
margin-top: auto;
color: #d97706 !important;
-webkit-text-fill-color: #d97706 !important;
font-size: 24px;
line-height: 1;
font-weight: 950;
}
@media (max-width: 920px) {
.vb-storage-twentyseven-filter {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-twentyseven-grid {
grid-template-columns: 1fr;
}
.vb-storage-twentyseven-sidebar h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This saved filters localStorage example is useful for ecommerce category pages, WooCommerce product filters, real estate listings, job boards, directories, comparison websites, blog archives, and searchable catalog interfaces.
A wishlist saved with localStorage is useful for ecommerce stores, affiliate websites, product catalogs, marketplaces, course websites, booking platforms, and comparison pages. It lets visitors save favorite items without needing an account or backend database.
This example lets users add products to a wishlist, remove products, clear the wishlist, and keep saved items after refreshing the page. JavaScript stores the wishlist as a JSON array in localStorage and updates the UI instantly.
Add items to the wishlist, refresh the page, and localStorage restores your saved favorites.
A clean website package for small businesses and service pages.
299€A custom booking form with saved form fields and smooth UI.
149€Technical SEO setup for structure, metadata, and internal links.
199€A lightweight browser feature built with custom JavaScript.
249€(function () {
const wrapper = document.querySelector("[data-vb-storage-twentyeight]");
if (!wrapper) return;
const storageKey = "vbStorageTwentyeightWishlist";
const products = Array.from(wrapper.querySelectorAll("[data-product]"));
const wishlistList = wrapper.querySelector("[data-wishlist-list]");
const wishlistCount = wrapper.querySelector("[data-wishlist-count]");
const clearButton = wrapper.querySelector("[data-clear-wishlist]");
let wishlist = [];
function saveWishlist() {
localStorage.setItem(storageKey, JSON.stringify(wishlist));
}
function loadWishlist() {
const savedWishlist = localStorage.getItem(storageKey);
if (!savedWishlist) return;
try {
const parsedWishlist = JSON.parse(savedWishlist);
wishlist = Array.isArray(parsedWishlist) ? parsedWishlist : [];
} catch (error) {
wishlist = [];
localStorage.removeItem(storageKey);
}
}
function getProductData(product) {
return {
id: product.getAttribute("data-id"),
name: product.getAttribute("data-name"),
price: product.getAttribute("data-price"),
tag: product.getAttribute("data-tag")
};
}
function renderWishlist() {
wishlistList.innerHTML = "";
products.forEach(function (product) {
const productId = product.getAttribute("data-id");
const isSaved = wishlist.some(function (item) {
return item.id === productId;
});
product.classList.toggle("is-saved", isSaved);
product.querySelector("[data-wishlist-button]").textContent = isSaved ? "Saved" : "Add to Wishlist";
});
wishlistCount.textContent = wishlist.length === 1 ? "1 saved" : wishlist.length + " saved";
if (wishlist.length === 0) {
wishlistList.innerHTML = '<p class="vb-storage-twentyeight-empty">No wishlist items saved yet.</p>';
saveWishlist();
return;
}
wishlist.forEach(function (item) {
const row = document.createElement("div");
row.className = "vb-storage-twentyeight-item";
row.innerHTML =
'<div>' +
'<strong>' + item.name + '</strong>' +
'<span>' + item.tag + ' · ' + item.price + '</span>' +
'</div>' +
'<button type="button" class="vb-storage-twentyeight-remove" data-remove-wishlist="' + item.id + '">×</button>';
wishlistList.appendChild(row);
});
saveWishlist();
}
function toggleWishlist(product) {
const productData = getProductData(product);
const alreadySaved = wishlist.some(function (item) {
return item.id === productData.id;
});
if (alreadySaved) {
wishlist = wishlist.filter(function (item) {
return item.id !== productData.id;
});
} else {
wishlist.unshift(productData);
}
renderWishlist();
}
products.forEach(function (product) {
product.querySelector("[data-wishlist-button]").addEventListener("click", function () {
toggleWishlist(product);
});
});
wishlistList.addEventListener("click", function (event) {
const removeId = event.target.getAttribute("data-remove-wishlist");
if (!removeId) return;
wishlist = wishlist.filter(function (item) {
return item.id !== removeId;
});
renderWishlist();
});
clearButton.addEventListener("click", function () {
wishlist = [];
localStorage.removeItem(storageKey);
renderWishlist();
});
loadWishlist();
renderWishlist();
})();
<div class="vb-storage-twentyeight-demo">
<div class="vb-storage-twentyeight-wishlist" data-vb-storage-twentyeight>
<div class="vb-storage-twentyeight-head">
<span class="vb-storage-twentyeight-kicker">Example 28</span>
<h3>Saved Wishlist</h3>
<p>Add items to the wishlist, refresh the page, and localStorage restores your saved favorites.</p>
</div>
<div class="vb-storage-twentyeight-layout">
<section class="vb-storage-twentyeight-products">
<article data-product data-id="starter-site" data-name="Starter Website" data-price="299€" data-tag="Website">
<span>Website</span>
<h4>Starter Website</h4>
<p>A clean website package for small businesses and service pages.</p>
<strong>299€</strong>
<button type="button" data-wishlist-button>Add to Wishlist</button>
</article>
<article data-product data-id="booking-form" data-name="Booking Form" data-price="149€" data-tag="Form">
<span>Form</span>
<h4>Booking Form</h4>
<p>A custom booking form with saved form fields and smooth UI.</p>
<strong>149€</strong>
<button type="button" data-wishlist-button>Add to Wishlist</button>
</article>
<article data-product data-id="seo-setup" data-name="SEO Setup" data-price="199€" data-tag="SEO">
<span>SEO</span>
<h4>SEO Setup</h4>
<p>Technical SEO setup for structure, metadata, and internal links.</p>
<strong>199€</strong>
<button type="button" data-wishlist-button>Add to Wishlist</button>
</article>
<article data-product data-id="custom-widget" data-name="Custom JS Widget" data-price="249€" data-tag="JavaScript">
<span>JavaScript</span>
<h4>Custom JS Widget</h4>
<p>A lightweight browser feature built with custom JavaScript.</p>
<strong>249€</strong>
<button type="button" data-wishlist-button>Add to Wishlist</button>
</article>
</section>
<aside class="vb-storage-twentyeight-panel">
<div class="vb-storage-twentyeight-panel-head">
<strong>Wishlist</strong>
<span data-wishlist-count>0 saved</span>
</div>
<div class="vb-storage-twentyeight-list" data-wishlist-list>
<p class="vb-storage-twentyeight-empty">No wishlist items saved yet.</p>
</div>
<button type="button" data-clear-wishlist>Clear Wishlist</button>
</aside>
</div>
</div>
</div>
.vb-storage-twentyeight-demo,
.vb-storage-twentyeight-demo * {
box-sizing: border-box;
}
.vb-storage-twentyeight-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(244, 63, 94, 0.16), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.15), transparent 34%),
linear-gradient(135deg, #fff1f2 0%, #faf5ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(244, 63, 94, 0.18);
box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}
.vb-storage-twentyeight-wishlist {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentyeight-head {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.vb-storage-twentyeight-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: #ffe4e6;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentyeight-head h3 {
max-width: 820px;
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentyeight-head p {
max-width: 780px;
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentyeight-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(320px, 390px);
gap: 20px;
align-items: start;
}
.vb-storage-twentyeight-products {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.vb-storage-twentyeight-products article {
display: grid;
align-content: start;
gap: 10px;
min-height: 250px;
padding: 18px;
border-radius: 26px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.24);
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}
.vb-storage-twentyeight-products article.is-saved {
border-color: rgba(244, 63, 94, 0.56);
background: linear-gradient(135deg, #fff1f2, #ffffff) !important;
}
.vb-storage-twentyeight-products article span {
display: inline-flex;
justify-self: start;
padding: 7px 10px;
border-radius: 999px;
background: #ffe4e6;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 11px;
font-weight: 950;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.vb-storage-twentyeight-products h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 23px !important;
line-height: 1.12 !important;
font-weight: 950 !important;
}
.vb-storage-twentyeight-products p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.55;
font-weight: 650;
}
.vb-storage-twentyeight-products strong {
margin-top: auto;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 26px;
line-height: 1;
font-weight: 950;
}
.vb-storage-twentyeight-products button,
.vb-storage-twentyeight-panel > button,
.vb-storage-twentyeight-remove {
min-height: 44px;
border: 0;
border-radius: 999px;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentyeight-products button {
background: linear-gradient(135deg, #f43f5e, #a855f7);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-twentyeight-products article.is-saved button {
background: #ffe4e6;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
}
.vb-storage-twentyeight-panel {
display: grid;
gap: 14px;
padding: 18px;
border-radius: 28px;
background: #111827;
box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}
.vb-storage-twentyeight-panel-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
.vb-storage-twentyeight-panel-head strong {
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 24px;
font-weight: 950;
}
.vb-storage-twentyeight-panel-head span {
color: #fecdd3 !important;
-webkit-text-fill-color: #fecdd3 !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-twentyeight-list {
display: grid;
gap: 10px;
min-height: 320px;
}
.vb-storage-twentyeight-empty {
display: grid;
place-items: center;
min-height: 320px;
margin: 0 !important;
border: 1px dashed rgba(255,255,255,0.22);
border-radius: 20px;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-twentyeight-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
padding: 12px;
border-radius: 18px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentyeight-item strong {
display: block;
margin-bottom: 4px;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: 14px;
line-height: 1.25;
font-weight: 900;
}
.vb-storage-twentyeight-item span {
color: #fecdd3 !important;
-webkit-text-fill-color: #fecdd3 !important;
font-size: 12px;
font-weight: 850;
}
.vb-storage-twentyeight-remove {
width: 34px;
height: 34px;
min-height: 34px;
background: #ffe4e6;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
font-size: 16px;
}
.vb-storage-twentyeight-panel > button {
background: #ffffff;
color: #be123c !important;
-webkit-text-fill-color: #be123c !important;
}
@media (max-width: 940px) {
.vb-storage-twentyeight-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.vb-storage-twentyeight-products {
grid-template-columns: 1fr;
}
.vb-storage-twentyeight-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This wishlist localStorage example is useful for ecommerce stores, affiliate product lists, marketplace cards, booking platforms, course catalogs, digital product shops, and WooCommerce-style favorite product features.
Saving multi-step form progress with localStorage is useful for quote request forms, checkout flows, onboarding forms, application forms, booking forms, surveys, and lead generation funnels. It prevents users from losing progress when they refresh or return later.
This example saves the current form step and entered field values. JavaScript restores the same step after refresh, keeps the typed data, updates the progress bar, and lets users reset the saved progress.
Fill the steps, refresh the page, and localStorage restores your current step and field values.
(function () {
const wrapper = document.querySelector("[data-vb-storage-twentynine]");
if (!wrapper) return;
const storageKey = "vbStorageTwentynineMultiStep";
const form = wrapper.querySelector("[data-multistep-form]");
const panels = Array.from(wrapper.querySelectorAll("[data-step-panel]"));
const fields = Array.from(form.querySelectorAll("input, select, textarea"));
const prevButton = wrapper.querySelector("[data-prev-step]");
const nextButton = wrapper.querySelector("[data-next-step]");
const resetButton = wrapper.querySelector("[data-reset-progress]");
const stepLabel = wrapper.querySelector("[data-step-label]");
const stepProgress = wrapper.querySelector("[data-step-progress]");
const summary = wrapper.querySelector("[data-form-summary]");
let state = {
step: 0,
data: {}
};
function saveState() {
localStorage.setItem(storageKey, JSON.stringify(state));
}
function loadState() {
const savedState = localStorage.getItem(storageKey);
if (!savedState) return;
try {
const parsedState = JSON.parse(savedState);
state.step = Number(parsedState.step) || 0;
state.data = parsedState.data || {};
} catch (error) {
localStorage.removeItem(storageKey);
}
}
function collectData() {
fields.forEach(function (field) {
state.data[field.name] = field.value;
});
}
function applyData() {
fields.forEach(function (field) {
field.value = state.data[field.name] || "";
});
}
function updateSummary() {
summary.textContent =
"Name: " + (state.data.name || "Not added") +
" · Project: " + (state.data.project || "Not selected") +
" · Budget: " + (state.data.budget || "Not selected");
}
function renderStep() {
panels.forEach(function (panel, index) {
panel.classList.toggle("is-active", index === state.step);
});
stepLabel.textContent = "Step " + (state.step + 1) + " of " + panels.length;
stepProgress.style.width = ((state.step + 1) / panels.length * 100) + "%";
prevButton.disabled = state.step === 0;
nextButton.textContent = state.step === panels.length - 1 ? "Finish Demo" : "Next";
updateSummary();
saveState();
}
fields.forEach(function (field) {
field.addEventListener("input", function () {
collectData();
updateSummary();
saveState();
});
field.addEventListener("change", function () {
collectData();
updateSummary();
saveState();
});
});
prevButton.addEventListener("click", function () {
collectData();
state.step = Math.max(0, state.step - 1);
renderStep();
});
nextButton.addEventListener("click", function () {
collectData();
if (state.step < panels.length - 1) {
state.step += 1;
renderStep();
return;
}
summary.textContent = "Demo finished. Your progress is still saved until you reset it.";
saveState();
});
resetButton.addEventListener("click", function () {
state = {
step: 0,
data: {}
};
localStorage.removeItem(storageKey);
form.reset();
renderStep();
});
loadState();
applyData();
renderStep();
})();
<div class="vb-storage-twentynine-demo">
<div class="vb-storage-twentynine-formapp" data-vb-storage-twentynine>
<div class="vb-storage-twentynine-intro">
<span class="vb-storage-twentynine-kicker">Example 29</span>
<h3>Saved Multi-Step Form</h3>
<p>Fill the steps, refresh the page, and localStorage restores your current step and field values.</p>
<div class="vb-storage-twentynine-progress">
<span data-step-label>Step 1 of 3</span>
<div><i data-step-progress></i></div>
</div>
</div>
<form class="vb-storage-twentynine-form" data-multistep-form>
<section data-step-panel="0" class="is-active">
<h4>Contact Details</h4>
<label>
<span>Name</span>
<input type="text" name="name" placeholder="Your name">
</label>
<label>
<span>Email</span>
<input type="email" name="email" placeholder="you@example.com">
</label>
</section>
<section data-step-panel="1">
<h4>Project Type</h4>
<label>
<span>What do you need?</span>
<select name="project">
<option value="">Choose project</option>
<option value="Website">Website</option>
<option value="Ecommerce">Ecommerce</option>
<option value="WordPress Plugin">WordPress Plugin</option>
<option value="JavaScript Feature">JavaScript Feature</option>
</select>
</label>
<label>
<span>Budget</span>
<select name="budget">
<option value="">Choose budget</option>
<option value="Under 500€">Under 500€</option>
<option value="500€ - 1500€">500€ - 1500€</option>
<option value="1500€+">1500€+</option>
</select>
</label>
</section>
<section data-step-panel="2">
<h4>Project Message</h4>
<label>
<span>Message</span>
<textarea name="message" rows="7" placeholder="Describe your project..."></textarea>
</label>
<div class="vb-storage-twentynine-summary" data-form-summary>
Your saved form summary will appear here.
</div>
</section>
<div class="vb-storage-twentynine-actions">
<button type="button" data-prev-step>Back</button>
<button type="button" data-next-step>Next</button>
<button type="button" data-reset-progress>Reset</button>
</div>
</form>
</div>
</div>
.vb-storage-twentynine-demo,
.vb-storage-twentynine-demo * {
box-sizing: border-box;
}
.vb-storage-twentynine-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.17), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
linear-gradient(135deg, #f0f9ff 0%, #eef2ff 56%, #ffffff 100%) !important;
border: 1px solid rgba(14, 165, 233, 0.18);
box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}
.vb-storage-twentynine-formapp {
display: grid;
grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
gap: 22px;
max-width: 1120px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}
.vb-storage-twentynine-intro,
.vb-storage-twentynine-form {
min-width: 0;
}
.vb-storage-twentynine-intro {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(18px, 3vw, 26px);
border-radius: 28px;
background: #0f172a;
}
.vb-storage-twentynine-kicker {
display: inline-flex;
align-self: flex-start;
margin-bottom: 16px;
padding: 8px 12px;
border-radius: 999px;
background: rgba(14, 165, 233, 0.16);
color: #bae6fd !important;
-webkit-text-fill-color: #bae6fd !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-twentynine-intro h3 {
margin: 0 0 16px !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-twentynine-intro p {
max-width: 560px;
margin: 0 0 22px !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-twentynine-progress {
display: grid;
gap: 9px;
padding: 15px;
border-radius: 20px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
}
.vb-storage-twentynine-progress span {
color: #e0f2fe !important;
-webkit-text-fill-color: #e0f2fe !important;
font-size: 13px;
font-weight: 900;
}
.vb-storage-twentynine-progress div {
height: 11px;
overflow: hidden;
border-radius: 999px;
background: rgba(255,255,255,0.12);
}
.vb-storage-twentynine-progress i {
display: block;
width: 33.33%;
height: 100%;
border-radius: 999px;
background: linear-gradient(135deg, #0ea5e9, #6366f1);
transition: width 0.25s ease;
}
.vb-storage-twentynine-form {
display: grid;
gap: 16px;
padding: clamp(18px, 3vw, 24px);
border-radius: 30px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.20);
}
.vb-storage-twentynine-form section {
display: none;
min-height: 340px;
align-content: start;
gap: 14px;
padding: clamp(18px, 3vw, 24px);
border-radius: 24px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.20);
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}
.vb-storage-twentynine-form section.is-active {
display: grid;
}
.vb-storage-twentynine-form h4 {
margin: 0 0 4px !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: clamp(28px, 4vw, 42px) !important;
line-height: 1.05 !important;
font-weight: 950 !important;
letter-spacing: -0.055em;
}
.vb-storage-twentynine-form label {
display: grid;
gap: 7px;
}
.vb-storage-twentynine-form label span {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-twentynine-form input,
.vb-storage-twentynine-form select,
.vb-storage-twentynine-form textarea {
width: 100%;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #f8fafc;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
font-weight: 700;
outline: none;
}
.vb-storage-twentynine-form input,
.vb-storage-twentynine-form select {
min-height: 50px;
padding: 0 15px;
}
.vb-storage-twentynine-form textarea {
resize: vertical;
padding: 14px 15px;
line-height: 1.55;
}
.vb-storage-twentynine-form input:focus,
.vb-storage-twentynine-form select:focus,
.vb-storage-twentynine-form textarea:focus {
border-color: rgba(14, 165, 233, 0.72);
box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.10);
}
.vb-storage-twentynine-summary {
padding: 14px;
border-radius: 18px;
background: #eff6ff;
color: #1e3a8a !important;
-webkit-text-fill-color: #1e3a8a !important;
font-size: 14px;
line-height: 1.6;
font-weight: 750;
}
.vb-storage-twentynine-actions {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 10px;
}
.vb-storage-twentynine-actions button {
min-height: 46px;
padding: 0 16px;
border: 0;
border-radius: 999px;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-twentynine-actions button:first-child {
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
}
.vb-storage-twentynine-actions button:nth-child(2) {
background: linear-gradient(135deg, #0ea5e9, #6366f1);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-twentynine-actions button:last-child {
background: #fee2e2;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
.vb-storage-twentynine-actions button:disabled {
opacity: 0.55;
cursor: not-allowed;
}
@media (max-width: 900px) {
.vb-storage-twentynine-formapp {
grid-template-columns: 1fr;
}
}
@media (max-width: 580px) {
.vb-storage-twentynine-actions {
grid-template-columns: 1fr;
}
.vb-storage-twentynine-intro h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This multi-step form progress localStorage example is useful for quote request forms, onboarding flows, checkout forms, booking forms, application forms, surveys, lead generation funnels, and long contact forms.
A localStorage CRUD app is one of the best JavaScript localStorage examples because it combines the most important browser storage patterns: create, read, update, and delete. It is useful for task managers, admin demos, dashboards, small browser apps, saved lists, and JavaScript portfolio projects.
This example lets users create records, edit existing records, delete records, search saved records, and restore everything after refresh. JavaScript stores the records as a JSON array in localStorage and rebuilds the interface whenever the data changes.
Create, edit, delete, search, and restore saved records using localStorage.
No records saved yet.
(function () {
const wrapper = document.querySelector("[data-vb-storage-thirty]");
if (!wrapper) return;
const storageKey = "vbStorageThirtyCrudRecords";
const form = wrapper.querySelector("[data-crud-form]");
const formTitle = wrapper.querySelector("[data-form-title]");
const titleInput = wrapper.querySelector("[data-record-title]");
const categoryInput = wrapper.querySelector("[data-record-category]");
const descriptionInput = wrapper.querySelector("[data-record-description]");
const saveButton = wrapper.querySelector("[data-save-record]");
const cancelButton = wrapper.querySelector("[data-cancel-edit]");
const searchInput = wrapper.querySelector("[data-record-search]");
const clearButton = wrapper.querySelector("[data-clear-records]");
const recordCount = wrapper.querySelector("[data-record-count]");
const recordList = wrapper.querySelector("[data-record-list]");
let records = [];
let editingId = null;
function saveRecords() {
localStorage.setItem(storageKey, JSON.stringify(records));
}
function loadRecords() {
const savedRecords = localStorage.getItem(storageKey);
if (!savedRecords) return;
try {
const parsedRecords = JSON.parse(savedRecords);
records = Array.isArray(parsedRecords) ? parsedRecords : [];
} catch (error) {
records = [];
localStorage.removeItem(storageKey);
}
}
function resetForm() {
editingId = null;
form.reset();
formTitle.textContent = "Add New Record";
saveButton.textContent = "Save Record";
cancelButton.hidden = true;
}
function getFilteredRecords() {
const search = searchInput.value.trim().toLowerCase();
if (!search) {
return records;
}
return records.filter(function (record) {
return (
record.title.toLowerCase().includes(search) ||
record.category.toLowerCase().includes(search) ||
record.description.toLowerCase().includes(search)
);
});
}
function renderRecords() {
const filteredRecords = getFilteredRecords();
recordList.innerHTML = "";
recordCount.textContent = records.length === 1
? "1 record saved"
: records.length + " records saved";
if (filteredRecords.length === 0) {
recordList.innerHTML = '<p class="vb-storage-thirty-empty">No records found.</p>';
return;
}
filteredRecords.forEach(function (record) {
const card = document.createElement("article");
card.className = "vb-storage-thirty-record";
card.innerHTML =
'<div class="vb-storage-thirty-record-top">' +
'<h5>' + record.title + '</h5>' +
'<span>' + record.category + '</span>' +
'</div>' +
'<p>' + record.description + '</p>' +
'<div class="vb-storage-thirty-actions">' +
'<button type="button" data-edit-record="' + record.id + '">Edit</button>' +
'<button type="button" data-delete-record="' + record.id + '">Delete</button>' +
'</div>';
recordList.appendChild(card);
});
}
function saveRecord() {
const title = titleInput.value.trim();
const category = categoryInput.value;
const description = descriptionInput.value.trim();
if (!title || !description) return;
if (editingId) {
records = records.map(function (record) {
if (record.id === editingId) {
return {
id: record.id,
title: title,
category: category,
description: description
};
}
return record;
});
} else {
records.unshift({
id: String(Date.now()),
title: title,
category: category,
description: description
});
}
saveRecords();
renderRecords();
resetForm();
}
function editRecord(recordId) {
const record = records.find(function (item) {
return item.id === recordId;
});
if (!record) return;
editingId = record.id;
titleInput.value = record.title;
categoryInput.value = record.category;
descriptionInput.value = record.description;
formTitle.textContent = "Edit Record";
saveButton.textContent = "Update Record";
cancelButton.hidden = false;
titleInput.focus();
}
function deleteRecord(recordId) {
records = records.filter(function (record) {
return record.id !== recordId;
});
if (editingId === recordId) {
resetForm();
}
saveRecords();
renderRecords();
}
form.addEventListener("submit", function (event) {
event.preventDefault();
saveRecord();
});
recordList.addEventListener("click", function (event) {
const editId = event.target.getAttribute("data-edit-record");
const deleteId = event.target.getAttribute("data-delete-record");
if (editId) editRecord(editId);
if (deleteId) deleteRecord(deleteId);
});
searchInput.addEventListener("input", renderRecords);
cancelButton.addEventListener("click", resetForm);
clearButton.addEventListener("click", function () {
records = [];
localStorage.removeItem(storageKey);
resetForm();
renderRecords();
});
loadRecords();
renderRecords();
})();
<div class="vb-storage-thirty-demo">
<div class="vb-storage-thirty-app" data-vb-storage-thirty>
<div class="vb-storage-thirty-head">
<span class="vb-storage-thirty-kicker">Example 30</span>
<h3>LocalStorage CRUD App</h3>
<p>Create, edit, delete, search, and restore saved records using localStorage.</p>
</div>
<div class="vb-storage-thirty-layout">
<form class="vb-storage-thirty-form" data-crud-form>
<h4 data-form-title>Add New Record</h4>
<label>
<span>Title</span>
<input type="text" data-record-title placeholder="Project title">
</label>
<label>
<span>Category</span>
<select data-record-category>
<option value="Website">Website</option>
<option value="JavaScript">JavaScript</option>
<option value="SEO">SEO</option>
<option value="WordPress">WordPress</option>
</select>
</label>
<label>
<span>Description</span>
<textarea data-record-description rows="5" placeholder="Short description..."></textarea>
</label>
<button type="submit" data-save-record>Save Record</button>
<button type="button" class="vb-storage-thirty-cancel" data-cancel-edit hidden>Cancel Edit</button>
</form>
<section class="vb-storage-thirty-records">
<div class="vb-storage-thirty-toolbar">
<input type="search" data-record-search placeholder="Search saved records...">
<button type="button" data-clear-records>Clear All</button>
</div>
<div class="vb-storage-thirty-count" data-record-count>0 records saved</div>
<div class="vb-storage-thirty-list" data-record-list>
<p class="vb-storage-thirty-empty">No records saved yet.</p>
</div>
</section>
</div>
</div>
</div>
.vb-storage-thirty-demo,
.vb-storage-thirty-demo * {
box-sizing: border-box;
}
.vb-storage-thirty-demo {
margin: 28px 0;
padding: clamp(18px, 4vw, 38px);
border-radius: 44px;
background:
radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.17), transparent 34%),
radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
linear-gradient(135deg, #eff6ff 0%, #f0fdfa 56%, #ffffff 100%) !important;
border: 1px solid rgba(37, 99, 235, 0.18);
box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}
.vb-storage-thirty-app {
max-width: 1160px;
margin: 0 auto;
padding: clamp(20px, 4vw, 34px);
border-radius: 34px;
background: #0f172a;
box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}
.vb-storage-thirty-head {
display: grid;
gap: 12px;
margin-bottom: 22px;
}
.vb-storage-thirty-kicker {
display: inline-flex;
justify-self: start;
padding: 8px 12px;
border-radius: 999px;
background: rgba(45, 212, 191, 0.16);
color: #99f6e4 !important;
-webkit-text-fill-color: #99f6e4 !important;
font-size: 12px;
font-weight: 950;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.vb-storage-thirty-head h3 {
max-width: 850px;
margin: 0 !important;
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
font-size: clamp(36px, 6vw, 66px) !important;
line-height: 0.96 !important;
font-weight: 950 !important;
letter-spacing: -0.075em;
}
.vb-storage-thirty-head p {
max-width: 760px;
margin: 0 !important;
color: #cbd5e1 !important;
-webkit-text-fill-color: #cbd5e1 !important;
font-size: 16px;
line-height: 1.7;
font-weight: 650;
}
.vb-storage-thirty-layout {
display: grid;
grid-template-columns: minmax(300px, 390px) minmax(0, 1fr);
gap: 18px;
align-items: start;
}
.vb-storage-thirty-form,
.vb-storage-thirty-records {
min-width: 0;
}
.vb-storage-thirty-form {
display: grid;
gap: 13px;
padding: clamp(18px, 3vw, 24px);
border-radius: 28px;
background: #ffffff;
}
.vb-storage-thirty-form h4 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 28px !important;
line-height: 1.08 !important;
font-weight: 950 !important;
letter-spacing: -0.05em;
}
.vb-storage-thirty-form label {
display: grid;
gap: 7px;
}
.vb-storage-thirty-form label span {
color: #334155 !important;
-webkit-text-fill-color: #334155 !important;
font-size: 13px;
font-weight: 850;
}
.vb-storage-thirty-form input,
.vb-storage-thirty-form select,
.vb-storage-thirty-form textarea,
.vb-storage-thirty-toolbar input {
width: 100%;
border: 1px solid rgba(148, 163, 184, 0.34);
border-radius: 16px;
background: #f8fafc;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 15px;
font-weight: 700;
outline: none;
}
.vb-storage-thirty-form input,
.vb-storage-thirty-form select,
.vb-storage-thirty-toolbar input {
min-height: 50px;
padding: 0 15px;
}
.vb-storage-thirty-form textarea {
resize: vertical;
padding: 14px 15px;
line-height: 1.55;
}
.vb-storage-thirty-form input:focus,
.vb-storage-thirty-form select:focus,
.vb-storage-thirty-form textarea:focus,
.vb-storage-thirty-toolbar input:focus {
border-color: rgba(20, 184, 166, 0.72);
box-shadow: 0 0 0 4px rgba(20, 184, 166, 0.10);
}
.vb-storage-thirty-form button,
.vb-storage-thirty-toolbar button,
.vb-storage-thirty-actions button {
min-height: 44px;
border: 0;
border-radius: 999px;
font-size: 13px;
font-weight: 950;
cursor: pointer;
}
.vb-storage-thirty-form button[type="submit"] {
background: linear-gradient(135deg, #2563eb, #14b8a6);
color: #ffffff !important;
-webkit-text-fill-color: #ffffff !important;
}
.vb-storage-thirty-cancel,
.vb-storage-thirty-toolbar button,
.vb-storage-thirty-actions button:last-child {
background: #fee2e2 !important;
color: #b91c1c !important;
-webkit-text-fill-color: #b91c1c !important;
}
.vb-storage-thirty-records {
display: grid;
gap: 12px;
padding: clamp(18px, 3vw, 24px);
border-radius: 28px;
background: #ffffff;
}
.vb-storage-thirty-toolbar {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
}
.vb-storage-thirty-toolbar button {
padding: 0 14px;
}
.vb-storage-thirty-count {
padding: 12px 14px;
border-radius: 18px;
background: #eff6ff;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
font-size: 13px;
font-weight: 950;
}
.vb-storage-thirty-list {
display: grid;
gap: 10px;
min-height: 430px;
}
.vb-storage-thirty-empty {
display: grid;
place-items: center;
min-height: 430px;
margin: 0 !important;
border: 1px dashed rgba(148, 163, 184, 0.55);
border-radius: 20px;
color: #64748b !important;
-webkit-text-fill-color: #64748b !important;
font-size: 14px;
font-weight: 750;
}
.vb-storage-thirty-record {
display: grid;
gap: 10px;
padding: 14px;
border-radius: 20px;
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
}
.vb-storage-thirty-record-top {
display: flex;
justify-content: space-between;
gap: 12px;
align-items: start;
}
.vb-storage-thirty-record h5 {
margin: 0 !important;
color: #0f172a !important;
-webkit-text-fill-color: #0f172a !important;
font-size: 19px !important;
line-height: 1.15 !important;
font-weight: 950 !important;
}
.vb-storage-thirty-record span {
flex: 0 0 auto;
padding: 7px 10px;
border-radius: 999px;
background: #ccfbf1;
color: #0f766e !important;
-webkit-text-fill-color: #0f766e !important;
font-size: 11px;
font-weight: 950;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.vb-storage-thirty-record p {
margin: 0 !important;
color: #475569 !important;
-webkit-text-fill-color: #475569 !important;
font-size: 14px;
line-height: 1.6;
font-weight: 650;
overflow-wrap: anywhere;
}
.vb-storage-thirty-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.vb-storage-thirty-actions button {
min-height: 36px;
padding: 0 12px;
}
.vb-storage-thirty-actions button:first-child {
background: #dbeafe;
color: #1d4ed8 !important;
-webkit-text-fill-color: #1d4ed8 !important;
}
@media (max-width: 940px) {
.vb-storage-thirty-layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 620px) {
.vb-storage-thirty-toolbar {
grid-template-columns: 1fr;
}
.vb-storage-thirty-head h3 {
font-size: 38px !important;
letter-spacing: -0.055em;
}
}
This localStorage CRUD app example is useful for task managers, saved lists, admin demos, browser-based apps, JavaScript portfolio projects, lightweight dashboards, and learning how to create, read, update, and delete data in localStorage.
JavaScript localStorage is simple to use, but the best localStorage features are planned carefully. A good implementation should store only useful data, keep the interface in sync with the saved value, handle invalid stored data safely, and give users a clear way to remove or reset saved information.
For SEO-focused websites, ecommerce pages, WordPress landing pages, SaaS dashboards, and interactive blog examples, localStorage works best when it improves usability without hiding important content from search engines. It should remember user actions, not replace meaningful HTML content that should be visible on the page.
Use unique localStorage keys for every feature, plugin, component, or demo so one saved value does not overwrite another.
Use localStorage for preferences, carts, drafts, filters, and UI state. Do not store passwords, private tokens, payment data, or confidential information.
Arrays and objects must be saved with JSON.stringify() and restored with JSON.parse(), because localStorage stores values as strings.
When data is added, edited, removed, or reset, update both localStorage and the visible interface at the same time.
When localStorage is used correctly, it can make small website features feel much more polished. A saved form draft, persistent cart, remembered dark mode setting, or restored filter state can reduce friction and make a website feel more useful without requiring a login system or database for every small interaction.
Many localStorage examples involve forms, product cards, dashboards, carts, lists, filters, tabs, and settings panels. These components often look fine on desktop but become hard to use on mobile if spacing, button size, scroll behavior, and layout changes are not planned.
A responsive localStorage UI should make saved data easy to understand on every screen size. Users should be able to add, remove, reset, edit, or restore saved items just as easily on a phone as they can on a desktop screen.
Use full-width buttons, readable labels, and enough spacing between action buttons such as save, remove, reset, next, back, and clear.
Saved status messages, restored draft notices, cart totals, and active filter labels should stay visible and easy to scan on small screens.
Use CSS grid or flexbox to move sidebars below content, stack product cards, and keep settings panels usable on mobile devices.
Responsive design is especially important for localStorage features because saved data often grows over time. A cart can get more items, a notes app can get longer text, a recent search list can expand, and a CRUD app can contain many records. The layout should stay usable even when the saved browser data is not empty.
LocalStorage is easy to start with, but there are common mistakes that can make a browser-based feature unreliable, insecure, or frustrating. Most problems happen when developers store the wrong data, forget to parse JSON safely, do not update the UI after changes, or use the same storage key in multiple places.
Passwords, private tokens, payment details, and confidential customer data should never be stored in localStorage.
Stored JSON can become invalid. Use try/catch before using parsed browser data in your interface.
Repeated keys can overwrite carts, forms, filters, or demo data. Every component should use its own unique key.
If a website remembers data, users should have a simple way to clear it, remove items, or reset the saved state.
The safest approach is to treat localStorage as a browser-based helper for user experience. It is excellent for saved interface state, but it should not be treated like a protected backend system. When the data is important, private, shared between devices, or connected to payments and accounts, use server-side storage instead.
Here are common questions about JavaScript localStorage examples, browser storage, saved form data, shopping carts, dark mode preferences, saved filters, recently viewed products, CRUD apps, and responsive UI components.
JavaScript localStorage is a browser storage feature that lets websites save small pieces of data on the visitor’s device. The data can remain available after refresh, after closing the tab, and after returning to the page later.
LocalStorage can be used for form drafts, shopping carts, dark mode preferences, saved filters, recent searches, recently viewed products, wishlists, notes, dashboard settings, quiz progress, tab state, accordion state, and small browser-based tools.
No. Passwords, private tokens, payment details, personal identity data, and confidential information should not be stored in localStorage. Use secure server-side storage and proper authentication systems for sensitive data.
Objects and arrays should be converted to strings with JSON.stringify() before saving. When reading the value back, use JSON.parse() to turn the string back into an object or array. It is best to wrap JSON.parse() in try/catch.
Yes. That is one of the main reasons localStorage is useful. It can keep data after a page refresh, so features like saved form drafts, carts, filters, and theme preferences can be restored when the page loads again.
Use localStorage for small, non-sensitive browser features that only need to exist on one device. Use a database when the data must be secure, shared between devices, connected to user accounts, used by other visitors, or stored permanently on the server.
JavaScript localStorage is one of the most practical browser features for building interactive website components that remember user actions. It can improve contact forms, quote request forms, ecommerce carts, dark mode toggles, saved filters, wishlists, recently viewed products, dashboard settings, CRUD apps, notes, quizzes, calculators, onboarding flows, and many other front-end UI patterns.
The best localStorage examples do more than save a value. They restore the interface after refresh, update the UI when data changes, use clear storage keys, support reset actions, handle JSON safely, and avoid storing sensitive information. That combination makes localStorage useful for real projects instead of only simple tutorials.
You can use the examples in this guide as starting points for WordPress pages, ecommerce websites, SaaS dashboards, landing pages, portfolios, learning projects, admin panels, and browser-based JavaScript tools. Customize the storage keys, layout, copy, colors, form fields, product data, and reset logic to match your own website or client project.
For production websites, remember the most important rule: localStorage is excellent for non-sensitive browser data, but secure data belongs on the server. Use it for user experience improvements, saved UI state, and practical front-end features — not for passwords, tokens, payments, or confidential customer details.
Continue building better website sections and interactive UI components with these related JavaScript and CSS guides. These posts work well together when building full landing pages, product pages, dashboards, ecommerce interfaces, forms, filters, menus, and responsive website layouts.