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:
localStoragekeeps 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.sessionStoragekeeps 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.
| Feature | localStorage | sessionStorage |
|---|---|---|
| How long it lasts | Until deleted by code or the user | Until the tab is closed |
| Shared between tabs | Yes, same site | No, one tab only |
| Typical size limit | About 5 MB per site | About 5 MB per site |
| Good for | Theme, language, saved drafts, cart | A 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:
| Feature | Web Storage | Cookies |
|---|---|---|
| Size | About 5 MB | About 4 KB per cookie |
| Sent to the server | Never, it stays in the browser | With every request to that site |
| Expiry | None (local) or tab close (session) | A date you choose |
| Read by | JavaScript on the page | The server, and JavaScript unless marked HttpOnly |
| Good for | Settings and data for the page itself | Logins 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 property | What it does | Example |
|---|---|---|
setItem(key, value) | Saves a value | localStorage.setItem("theme", "dark") |
getItem(key) | Reads a value, or null if missing | localStorage.getItem("theme") |
removeItem(key) | Deletes one item | localStorage.removeItem("theme") |
clear() | Deletes everything for this site | localStorage.clear() |
key(index) | Gets the key name at a position | localStorage.key(0) |
length | How many items are saved | localStorage.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 isnull(nothing saved yet), use"light"".select.value = savedshows the saved choice in the menu.classList.toggle("dark", condition)adds thedarkclass 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". UseNumber(localStorage.getItem("visits"))before you do maths, or"5" + 1gives"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,
setItemthrows an error calledQuotaExceededError. 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
localStoragekeeps data with no expiry and shares it across tabs;sessionStoragelasts for one tab.- Use
setItem,getItem,removeItemandclear; values are always strings. - Store lists and objects with
JSON.stringify()and read them withJSON.parse(). - The
storageevent tells other tabs that data changed. - About 5 MB per site, readable by any script on the page: never store secrets.