Web Storage

Web Storage lets a page save small amounts of data in the browser, so settings, drafts and preferences survive a page reload. localStorage keeps data until it's deleted; sessionStorage keeps it only for the current tab. Both are simple key–value stores of strings.

Saving and reading

JS basics.js
localStorage.setItem("theme", "dark");

const theme = localStorage.getItem("theme");   // "dark"
const missing = localStorage.getItem("nope");  // null

localStorage.removeItem("theme");
localStorage.clear();                          // removes everything for this site
console.log(localStorage.length);              // number of stored keys
MethodDoes
setItem(key, value)Saves a value (converted to a string)
getItem(key)Returns the string, or null if not found
removeItem(key)Deletes one key
clear()Deletes all keys for this origin
key(i), lengthEnumerate stored keys

A remembered preference

Pick a colour, then press Reset on the editor (or reload the page) — the choice is remembered:

Try it yourself
Result

The try/catch blocks matter: storage can be unavailable — in some private-browsing modes, when the user blocks site data, or inside sandboxed frames — and accessing it then throws an error. Your page should still work without it.

Storing objects with JSON

Storage only holds strings. Storing an object directly saves the useless text "[object Object]", so convert with JSON (lesson 41):

JS json.js
const cart = [{ id: 1, qty: 2 }, { id: 7, qty: 1 }];
localStorage.setItem("cart", JSON.stringify(cart));

const restored = JSON.parse(localStorage.getItem("cart") ?? "[]");
console.log(restored[1].id); // 7

A small helper keeps this tidy and handles missing or corrupted data:

JS store.js
const store = {
  get(key, fallback) {
    try {
      const raw = localStorage.getItem(key);
      return raw === null ? fallback : JSON.parse(raw);
    } catch {
      return fallback;
    }
  },
  set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch {
      return false; // unavailable, or quota exceeded
    }
  },
};

const prefs = store.get("prefs", { fontSize: 16 });
store.set("prefs", { ...prefs, fontSize: 18 });

localStorage vs sessionStorage

localStoragesessionStorage
LifetimeUntil deleted by code or the userUntil the tab is closed
Shared between tabs?Yes, across all tabs of the same siteNo, each tab has its own
Good forTheme, language, dismissed banners, draftsMulti-step form progress, one-off state

Both are scoped to the origin (protocol + domain + port), so one site can't read another's data.

Syncing between tabs

When localStorage changes in one tab, every other tab of the same site receives a storage event:

JS sync.js
window.addEventListener("storage", event => {
  if (event.key === "theme") {
    document.documentElement.dataset.theme = event.newValue;
  }
});

Limits and cautions

  • Size: typically about 5 MB per origin. Writing beyond the limit throws a QuotaExceededError.
  • Synchronous: reads and writes block the page briefly. Fine for small values; for large data use IndexedDB.
  • Not secure: any script on the page can read it, including a malicious one injected through an XSS bug. Never store passwords, and think carefully before storing authentication tokens — HTTP-only cookies are safer for those.
  • Not guaranteed: users clear site data, and browsers may evict storage for rarely visited sites.

Other storage options

APIUse for
CookiesSmall values the server needs on every request, like session IDs
IndexedDBLarge or structured data, offline apps; asynchronous
Cache APIStoring network responses for offline use (with service workers)