Complete HTML Course Module 14: Advanced: HTML Web APIs

HTML Web Storage API: localStorage and sessionStorage

  • Beginner
  • Lesson 14.4
  • 6 min read
  • 61 of 69 in the course

In short

The HTML Web Storage API lets a page save data in the browser with localStorage and sessionStorage, so settings, drafts and carts survive a page reload. Imagine a user picks dark mode, then reloads the page and it is bright again. Annoying! With Web Storage, the page remembers.

The HTML Web Storage API lets a page save data in the browser with localStorage and sessionStorage, so settings, drafts and carts survive a page reload.

Imagine a user picks dark mode, then reloads the page and it is bright again. Annoying! With Web Storage, the page remembers. In this lesson you will learn both storage types, all their methods, how to store lists and objects, and how to keep tabs in sync.

localStorage vs sessionStorage

The browser gives every website (every origin: the scheme, host and port, like https://shop.example.com) two small storage boxes:

  • localStorage keeps data with no expiry date. It is still there after the user closes the browser and comes back next week. It is shared by all tabs of the same site.
  • sessionStorage keeps data only for one tab. When the tab is closed, the data is gone. Two tabs of the same site each have their own sessionStorage.

Think of localStorage as a notebook you keep in your bag, and sessionStorage as a sticky note you throw away when you leave the room.

FeaturelocalStoragesessionStorage
How long it lastsUntil deleted by code or the userUntil the tab is closed
Shared between tabsYes, same siteNo, one tab only
Typical size limitAbout 5 MB per siteAbout 5 MB per site
Good forTheme, language, saved drafts, cartA form wizard step, one-visit filters

How is Web Storage different from cookies?

Cookies are small pieces of data the browser also stores, but they work differently:

FeatureWeb StorageCookies
SizeAbout 5 MBAbout 4 KB per cookie
Sent to the serverNever, it stays in the browserWith every request to that site
ExpiryNone (local) or tab close (session)A date you choose
Read byJavaScript on the pageThe server, and JavaScript unless marked HttpOnly
Good forSettings and data for the page itselfLogins and data the server must see

Because cookies travel with every request, they make each request a bit bigger. Use Web Storage for data only the page needs, and leave logins to secure HttpOnly cookies set by the server.

Web Storage methods

Both storage types have the same simple methods. Keys and values are always strings (text).

Method or propertyWhat it doesExample
setItem(key, value)Saves a valuelocalStorage.setItem("theme", "dark")
getItem(key)Reads a value, or null if missinglocalStorage.getItem("theme")
removeItem(key)Deletes one itemlocalStorage.removeItem("theme")
clear()Deletes everything for this sitelocalStorage.clear()
key(index)Gets the key name at a positionlocalStorage.key(0)
lengthHow many items are savedlocalStorage.length

Try this in the browser console:

localStorage.setItem("username", "Maya");
console.log(localStorage.getItem("username")); // Output: Maya
console.log(localStorage.getItem("age"));      // Output: null
localStorage.removeItem("username");
console.log(localStorage.length);              // Output: 0 (if nothing else is saved)

You can see and edit everything you saved in DevTools: open the Application tab (Chrome and Edge) or Storage tab (Firefox), then Local storage.

Example: remember the user's theme

<label for="theme">Theme</label>
<select id="theme">
  <option value="light">Light</option>
  <option value="dark">Dark</option>
</select>

<style>
  body.dark { background: #1e1e1e; color: #f1f1f1; }
</style>

<script>
  const select = document.querySelector("#theme");
  const saved = localStorage.getItem("theme") ?? "light";

  select.value = saved;
  document.body.classList.toggle("dark", saved === "dark");

  select.addEventListener("change", () => {
    localStorage.setItem("theme", select.value);
    document.body.classList.toggle("dark", select.value === "dark");
  });
</script>
  • getItem("theme") ?? "light" reads the saved theme. The ?? means "if it is null (nothing saved yet), use "light"".
  • select.value = saved shows the saved choice in the menu.
  • classList.toggle("dark", condition) adds the dark class when the condition is true and removes it otherwise.
  • When the user changes the menu, the new value is saved and applied.

Choose Dark, reload the page, and it stays dark.

Storing objects and lists as JSON

Because storage only holds strings, saving a list directly goes wrong:

localStorage.setItem("cart", ["apples", "bread"]);
console.log(localStorage.getItem("cart")); // Output: apples,bread  (just text, not a list)

The fix is JSON, a text format for data. JSON.stringify() turns a list or object into text, and JSON.parse() turns it back:

const cart = [
  { name: "Apples", qty: 3 },
  { name: "Bread", qty: 1 }
];

localStorage.setItem("cart", JSON.stringify(cart));

const savedCart = JSON.parse(localStorage.getItem("cart") ?? "[]");
console.log(savedCart[0].name); // Output: Apples
console.log(savedCart.length);  // Output: 2
  • JSON.stringify(cart) saves the text [{"name":"Apples","qty":3},{"name":"Bread","qty":1}].
  • localStorage.getItem("cart") ?? "[]" reads that text, or an empty list "[]" if nothing is saved.
  • JSON.parse(...) turns the text back into a real list you can use.

Common mistake: Forgetting that numbers come back as strings too. localStorage.setItem("visits", 5) saves "5". Use Number(localStorage.getItem("visits")) before you do maths, or "5" + 1 gives "51".

The storage event: keeping tabs in sync

When one tab changes localStorage, the browser fires a storage event in all other open tabs of the same site. (Not in the tab that made the change.) You can use it to update those tabs instantly:

<p>Items in your cart: <strong id="count">0</strong></p>
<button type="button" id="add">Add an item</button>

<script>
  const count = document.querySelector("#count");
  const show = () => { count.textContent = localStorage.getItem("cartCount") ?? "0"; };

  show();

  document.querySelector("#add").addEventListener("click", () => {
    const next = Number(localStorage.getItem("cartCount") ?? 0) + 1;
    localStorage.setItem("cartCount", next);
    show();
  });

  window.addEventListener("storage", (event) => {
    if (event.key === "cartCount") show();
  });
</script>

Open this page in two tabs side by side and click "Add an item" in one. The number updates in the other tab too. event.key tells you which item changed; you can also read event.oldValue and event.newValue.

Limits and privacy

  • Size: about 5 MB per site in most browsers. If you go over, setItem throws an error called QuotaExceededError. For large data, use IndexedDB, a bigger browser database.
  • It can disappear. Users can clear site data, and private or incognito windows delete it when closed. Never keep the only copy of important data there.
  • Not secure: any JavaScript on your page, including third-party scripts, can read it. Never store passwords, tokens or personal data like ID numbers in Web Storage.
  • It is synchronous: reading and writing pauses the page for a moment, so keep the data small.
  • Privacy laws such as the GDPR may treat stored data like cookies. Storing data the user asked for (like their theme) is usually fine; tracking them is not.

Tip: Wrap storage code in try { ... } catch { ... } in real projects. Some browsers block storage completely in certain privacy settings, and your page should still work without it.

Practice exercise

Build a "Notes" page with a <textarea> and a "Clear" button. Save the text to localStorage every time the user types, and load it when the page opens. The "Clear" button should empty the textarea and remove the saved note.

Hint: Listen for the input event on the textarea and call setItem("note", textarea.value). On load, set textarea.value = localStorage.getItem("note") ?? "".

Key takeaways

  • localStorage keeps data with no expiry and shares it across tabs; sessionStorage lasts for one tab.
  • Use setItem, getItem, removeItem and clear; values are always strings.
  • Store lists and objects with JSON.stringify() and read them with JSON.parse().
  • The storage event tells other tabs that data changed.
  • About 5 MB per site, readable by any script on the page: never store secrets.