LocalStorage and SessionStorage
Web Storage provides two mechanisms for storing data in the browser: localStorage and sessionStorage. Both offer simple key-value storage without needing a database or server.
localStorage vs sessionStorage
| Feature | localStorage | sessionStorage |
|---|---|---|
| Lifespan | Persists forever | Until tab closes |
| Scope | Shared across all tabs | One tab only |
| Capacity | ~5-10 MB | ~5-10 MB |
| Use case | User preferences | Temporary session data |
localStorage Basics
// Store data
localStorage.setItem('username', 'Alice');
localStorage.setItem('theme', 'dark');
// Retrieve data
const username = localStorage.getItem('username');
console.log(username); // "Alice"
// Remove item
localStorage.removeItem('theme');
// Clear all data
localStorage.clear();
// Check if key exists
if (localStorage.getItem('username') !== null) {
console.log('Username is stored');
}
Storing Different Data Types
localStorage only stores strings. Convert other types:
// Numbers (convert to/from string)
localStorage.setItem('count', '42');
const count = parseInt(localStorage.getItem('count'));
// Booleans (convert to/from string)
localStorage.setItem('isLoggedIn', 'true');
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
// Objects and Arrays (use JSON)
const user = {
id: 123,
name: 'Alice',
email: 'alice@example.com'
};
localStorage.setItem('user', JSON.stringify(user));
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser.name); // "Alice"
// Arrays
const todos = ['Buy milk', 'Walk dog', 'Code'];
localStorage.setItem('todos', JSON.stringify(todos));
const storedTodos = JSON.parse(localStorage.getItem('todos'));
Helper Functions
Create utility functions for easier use:
const storage = {
// Set any type of data
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
// Get any type of data
get(key, defaultValue = null) {
const value = localStorage.getItem(key);
if (value === null) return defaultValue;
try {
return JSON.parse(value);
} catch {
return value; // Return as string if not JSON
}
},
// Remove item
remove(key) {
localStorage.removeItem(key);
},
// Clear all
clear() {
localStorage.clear();
},
// Check if key exists
has(key) {
return localStorage.getItem(key) !== null;
}
};
// Usage
storage.set('user', { name: 'Alice', age: 30 });
storage.set('count', 42);
storage.set('active', true);
const user = storage.get('user');
const count = storage.get('count');
const theme = storage.get('theme', 'light'); // Default value
Real-World Examples
Dark Mode Toggle
// Check saved preference on page load
function loadTheme() {
const theme = localStorage.getItem('theme') || 'light';
document.body.className = theme;
return theme;
}
// Toggle dark mode
function toggleDarkMode() {
const currentTheme = document.body.className;
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.body.className = newTheme;
localStorage.setItem('theme', newTheme);
}
// Apply on page load
loadTheme();
// Toggle button
document.querySelector('#theme-toggle').addEventListener('click', toggleDarkMode);
User Preferences
class UserPreferences {
constructor() {
this.key = 'userPreferences';
}
get() {
const prefs = localStorage.getItem(this.key);
return prefs ? JSON.parse(prefs) : this.defaults();
}
defaults() {
return {
theme: 'light',
fontSize: 16,
notifications: true,
language: 'en'
};
}
set(key, value) {
const prefs = this.get();
prefs[key] = value;
localStorage.setItem(this.key, JSON.stringify(prefs));
}
apply() {
const prefs = this.get();
document.body.className = prefs.theme;
document.body.style.fontSize = `${prefs.fontSize}px`;
// Apply other preferences...
}
}
// Usage
const preferences = new UserPreferences();
preferences.apply(); // Apply on page load
// Change preference
preferences.set('theme', 'dark');
preferences.set('fontSize', 18);
preferences.apply();
Shopping Cart
class ShoppingCart {
constructor() {
this.key = 'shoppingCart';
}
getItems() {
const cart = localStorage.getItem(this.key);
return cart ? JSON.parse(cart) : [];
}
addItem(product) {
const items = this.getItems();
// Check if item already in cart
const existing = items.find(item => item.id === product.id);
if (existing) {
existing.quantity += 1;
} else {
items.push({ ...product, quantity: 1 });
}
localStorage.setItem(this.key, JSON.stringify(items));
this.updateBadge();
}
removeItem(productId) {
let items = this.getItems();
items = items.filter(item => item.id !== productId);
localStorage.setItem(this.key, JSON.stringify(items));
this.updateBadge();
}
updateQuantity(productId, quantity) {
const items = this.getItems();
const item = items.find(i => i.id === productId);
if (item) {
item.quantity = quantity;
localStorage.setItem(this.key, JSON.stringify(items));
this.updateBadge();
}
}
getTotalItems() {
return this.getItems().reduce((sum, item) => sum + item.quantity, 0);
}
getTotalPrice() {
return this.getItems().reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
}
updateBadge() {
const badge = document.querySelector('#cart-badge');
if (badge) {
badge.textContent = this.getTotalItems();
}
}
clear() {
localStorage.removeItem(this.key);
this.updateBadge();
}
}
// Usage
const cart = new ShoppingCart();
// Add to cart
cart.addItem({ id: 1, name: 'Laptop', price: 999 });
cart.addItem({ id: 2, name: 'Mouse', price: 29 });
// Display cart
const items = cart.getItems();
console.log('Total:', cart.getTotalPrice());
Form Auto-Save (Draft)
// Save form data as user types
function setupAutoSave(formId) {
const form = document.querySelector(formId);
const storageKey = `draft_${formId}`;
// Load saved draft
function loadDraft() {
const draft = localStorage.getItem(storageKey);
if (draft) {
const data = JSON.parse(draft);
Object.keys(data).forEach(key => {
const field = form.querySelector(`[name="${key}"]`);
if (field) field.value = data[key];
});
}
}
// Save draft
function saveDraft() {
const data = {};
const inputs = form.querySelectorAll('input, textarea');
inputs.forEach(input => {
data[input.name] = input.value;
});
localStorage.setItem(storageKey, JSON.stringify(data));
}
// Clear draft
function clearDraft() {
localStorage.removeItem(storageKey);
}
// Auto-save on input
form.addEventListener('input', saveDraft);
// Clear draft on successful submit
form.addEventListener('submit', (e) => {
clearDraft();
});
// Load draft on page load
loadDraft();
}
// Usage
setupAutoSave('#contact-form');
sessionStorage
Same API as localStorage, but data clears when tab closes:
// Store for this session only
sessionStorage.setItem('tempData', 'value');
// Retrieve
const temp = sessionStorage.getItem('tempData');
// Remove
sessionStorage.removeItem('tempData');
// Clear all
sessionStorage.clear();
Use cases for sessionStorage:
- Multi-step forms (wizard state)
- Temporary filters/search results
- Authentication tokens (if you want logout on tab close)
- Page navigation state
Multi-Step Form Example
class FormWizard {
constructor() {
this.key = 'wizardData';
}
saveStep(step, data) {
const wizardData = this.getAllData();
wizardData[step] = data;
sessionStorage.setItem(this.key, JSON.stringify(wizardData));
}
getStep(step) {
const wizardData = this.getAllData();
return wizardData[step] || {};
}
getAllData() {
const data = sessionStorage.getItem(this.key);
return data ? JSON.parse(data) : {};
}
clear() {
sessionStorage.removeItem(this.key);
}
}
// Usage
const wizard = new FormWizard();
// Step 1: Personal info
wizard.saveStep('personal', {
name: 'Alice',
email: 'alice@example.com'
});
// Step 2: Address
wizard.saveStep('address', {
street: '123 Main St',
city: 'Boston'
});
// Final step: Get all data
const allData = wizard.getAllData();
console.log(allData);
// {
// personal: { name: 'Alice', email: '...' },
// address: { street: '...', city: '...' }
// }
Storage Events
Listen for storage changes (from other tabs):
// Listen for changes from other tabs
window.addEventListener('storage', (e) => {
console.log('Key changed:', e.key);
console.log('Old value:', e.oldValue);
console.log('New value:', e.newValue);
console.log('Storage area:', e.storageArea);
// React to changes
if (e.key === 'theme') {
document.body.className = e.newValue;
}
});
Note: Storage event only fires in other tabs, not the current tab.
Storage Limits and Errors
function safeSetItem(key, value) {
try {
localStorage.setItem(key, value);
return true;
} catch (e) {
if (e.name === 'QuotaExceededError') {
console.error('Storage quota exceeded!');
// Handle: clear old data, notify user, etc.
} else if (e.name === 'SecurityError') {
console.error('Storage not available (private browsing?)');
}
return false;
}
}
// Usage
if (!safeSetItem('bigData', hugeString)) {
alert('Could not save data - storage full');
}
Checking Availability
function storageAvailable(type) {
try {
const storage = window[type];
const test = '__storage_test__';
storage.setItem(test, test);
storage.removeItem(test);
return true;
} catch {
return false;
}
}
// Check before using
if (storageAvailable('localStorage')) {
localStorage.setItem('key', 'value');
} else {
console.warn('localStorage not available');
// Use cookies or in-memory storage as fallback
}
Best Practices
✅ DO:
- Always use try/catch for storage operations
- Use JSON.stringify/parse for objects
- Provide default values when getting items
- Clear sensitive data when done
- Check storage availability before using
❌ DON’T:
- Store sensitive data (passwords, credit cards)
- Store large amounts of data (>5MB)
- Assume storage is always available
- Store executable code
- Trust data from storage (validate it)
Security Considerations
// ❌ NEVER store sensitive data
localStorage.setItem('password', 'secret123'); // NO!
localStorage.setItem('creditCard', '1234...'); // NO!
localStorage.setItem('ssn', '123-45-6789'); // NO!
// ✅ Safe to store
localStorage.setItem('theme', 'dark'); // OK
localStorage.setItem('language', 'en'); // OK
localStorage.setItem('preferences', '...'); // OK
Why?
- localStorage is accessible to all JavaScript on your domain
- XSS attacks can steal data from localStorage
- Data persists even after logout
- Not encrypted
Summary
| Operation | localStorage | sessionStorage |
|---|---|---|
| Set item | localStorage.setItem(key, val) |
sessionStorage.setItem(key, val) |
| Get item | localStorage.getItem(key) |
sessionStorage.getItem(key) |
| Remove item | localStorage.removeItem(key) |
sessionStorage.removeItem(key) |
| Clear all | localStorage.clear() |
sessionStorage.clear() |
| Lifespan | Forever | Until tab closes |
| Scope | All tabs | Single tab |
Next Article: What is the DOM (Review)