Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
14 minLesson 20 of 35
DOM & Browser APIs

Local Storage & Session Storage

Local Storage & Session Storage

Browser storage lets you persist data on the user's device without a server. It's used for user preferences, cart contents, auth tokens, cached data, and offline functionality.

The Two Options

FeaturelocalStoragesessionStorage
LifetimeUntil clearedUntil tab closes
ScopeAll tabs, same originCurrent tab only
Limit~5-10MB~5-10MB
Shared across tabsYesNo

Both have identical APIs. The choice depends on how long you need the data.

Core API

// Store a value
localStorage.setItem("theme", "dark");
localStorage.setItem("language", "en");

// Read a value
const theme = localStorage.getItem("theme");  // "dark"
const missing = localStorage.getItem("xyz");  // null (not undefined)

// Remove one item
localStorage.removeItem("theme");

// Clear everything
localStorage.clear();

// Number of stored items
localStorage.length;  // 1

// Iterate all keys
for (let i = 0; i < localStorage.length; i++) {
    const key = localStorage.key(i);
    const value = localStorage.getItem(key);
    console.log(key, value);
}

Storing Objects

localStorage only stores strings. JSON handles serialization:

// Store an object
const user = { id: 1, name: "Alice", role: "admin" };
localStorage.setItem("user", JSON.stringify(user));

// Retrieve it
const stored = localStorage.getItem("user");
const user = stored ? JSON.parse(stored) : null;

// Helper utility (recommended pattern)
const storage = {
    get(key, defaultValue = null) {
        try {
            const item = localStorage.getItem(key);
            return item ? JSON.parse(item) : defaultValue;
        } catch {
            return defaultValue;
        }
    },
    
    set(key, value) {
        localStorage.setItem(key, JSON.stringify(value));
    },
    
    remove(key) {
        localStorage.removeItem(key);
    },
    
    clear() {
        localStorage.clear();
    }
};

// Usage
storage.set("cart", [{ id: 1, qty: 2 }, { id: 3, qty: 1 }]);
const cart = storage.get("cart", []);

Practical Use Cases

User Preferences

const PREFS_KEY = "user_preferences";

const defaultPrefs = {
    theme: "light",
    language: "en",
    fontSize: 16,
    notifications: true
};

function getPrefs() {
    return { ...defaultPrefs, ...storage.get(PREFS_KEY, {}) };
}

function savePrefs(updates) {
    const current = getPrefs();
    storage.set(PREFS_KEY, { ...current, ...updates });
    applyPrefs();
}

function applyPrefs() {
    const { theme, fontSize } = getPrefs();
    document.documentElement.setAttribute("data-theme", theme);
    document.documentElement.style.fontSize = `${fontSize}px`;
}

// Apply on load
applyPrefs();

// Toggle theme
document.querySelector("#theme-toggle").addEventListener("click", () => {
    const { theme } = getPrefs();
    savePrefs({ theme: theme === "light" ? "dark" : "light" });
});

Shopping Cart

const CART_KEY = "shopping_cart";

const cart = {
    getItems() {
        return storage.get(CART_KEY, []);
    },
    
    addItem(product) {
        const items = this.getItems();
        const existing = items.find(i => i.id === product.id);
        
        if (existing) {
            existing.qty += 1;
        } else {
            items.push({ ...product, qty: 1 });
        }
        
        storage.set(CART_KEY, items);
        this.updateUI();
    },
    
    removeItem(productId) {
        const items = this.getItems().filter(i => i.id !== productId);
        storage.set(CART_KEY, items);
        this.updateUI();
    },
    
    getTotal() {
        return this.getItems().reduce((sum, i) => sum + i.price * i.qty, 0);
    },
    
    updateUI() {
        const count = this.getItems().reduce((n, i) => n + i.qty, 0);
        document.querySelector(".cart-count").textContent = count;
    }
};

Storage Events

When localStorage changes in another tab, a storage event fires:

window.addEventListener("storage", (event) => {
    console.log(event.key);        // which key changed
    console.log(event.oldValue);   // previous value (string)
    console.log(event.newValue);   // new value (string)
    console.log(event.storageArea); // localStorage or sessionStorage
    
    // Sync state across tabs
    if (event.key === "user") {
        const user = JSON.parse(event.newValue);
        updateUserUI(user);
    }
    
    if (event.key === "user" && event.newValue === null) {
        // User logged out in another tab
        redirectToLogin();
    }
});

When NOT to Use localStorage

// ❌ Never store sensitive data here
localStorage.setItem("password", password);  // readable by any JS on your domain
localStorage.setItem("credit_card", number); // XSS would steal it

// ✅ Auth tokens: use httpOnly cookies instead
// They're inaccessible to JavaScript and safe from XSS

// ❌ Don't store large data (videos, images)
// Use IndexedDB for anything over a few MB

// ❌ Don't treat it as reliable — users can clear it
// Always have a server-side source of truth

sessionStorage Use Cases

// Multi-step form — keep data until user finishes or closes tab
function saveFormProgress(step, data) {
    const saved = JSON.parse(sessionStorage.getItem("form_progress") || "{}");
    saved[step] = data;
    sessionStorage.setItem("form_progress", JSON.stringify(saved));
}

function getFormProgress(step) {
    const saved = JSON.parse(sessionStorage.getItem("form_progress") || "{}");
    return saved[step] || null;
}

// Scroll position restoration on back navigation
window.addEventListener("beforeunload", () => {
    sessionStorage.setItem("scrollY", window.scrollY.toString());
});

const savedScroll = parseInt(sessionStorage.getItem("scrollY") || "0");
window.scrollTo(0, savedScroll);

Storage Limits

// Check available space
function getStorageSize() {
    let total = 0;
    for (const key of Object.keys(localStorage)) {
        total += localStorage.getItem(key).length * 2; // UTF-16 = 2 bytes per char
    }
    return `${(total / 1024).toFixed(2)} KB`;
}

// Handle quota exceeded
try {
    localStorage.setItem("large", bigData);
} catch (e) {
    if (e.name === "QuotaExceededError") {
        // Clear old data, then retry
        localStorage.removeItem("cache");
        localStorage.setItem("large", bigData);
    }
}

Next lesson: The Event Loop & Call Stack — understanding JavaScript's concurrency model.

📱

Get this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!