Learning Objectives
- Store and retrieve data with localStorage
- Work with JSON data in storage
- Understand storage limits and security
- Handle storage events
- Apply storage best practices
Basic Usage
// Store data (key-value pairs)
localStorage.setItem('username', 'John');
localStorage.setItem('theme', 'dark');
localStorage.setItem('fontSize', '16');
// Retrieve data
const username = localStorage.getItem('username'); // 'John'
const theme = localStorage.getItem('theme'); // 'dark'
// Alternative syntax
localStorage.username = 'Jane';
const name = localStorage.username;
// Remove specific item
localStorage.removeItem('fontSize');
// Clear all data
localStorage.clear();
// Check if key exists
if (localStorage.getItem('theme')) {
console.log('Theme is set');
}
// Get number of items
console.log(localStorage.length);
// Get key by index
const firstKey = localStorage.key(0);
Storing Objects
Important: LocalStorage only stores strings. Use JSON.stringify() and JSON.parse() for objects.
// Store object
const user = {
name: 'John Doe',
email: 'john@example.com',
age: 30,
preferences: {
theme: 'dark',
notifications: true
}
};
// Convert to JSON string
localStorage.setItem('user', JSON.stringify(user));
// Retrieve and parse
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser.name); // 'John Doe'
console.log(storedUser.preferences.theme); // 'dark'
// Store array
const todos = ['Learn JavaScript', 'Build project', 'Deploy'];
localStorage.setItem('todos', JSON.stringify(todos));
const storedTodos = JSON.parse(localStorage.getItem('todos'));
console.log(storedTodos[0]); // 'Learn JavaScript'
Storage Helper Class
class Storage {
static set(key, value) {
try {
const serialized = JSON.stringify(value);
localStorage.setItem(key, serialized);
return true;
} catch (error) {
console.error('Storage error:', error);
return false;
}
}
static get(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.error('Parse error:', error);
return defaultValue;
}
}
static remove(key) {
localStorage.removeItem(key);
}
static clear() {
localStorage.clear();
}
static has(key) {
return localStorage.getItem(key) !== null;
}
static keys() {
return Object.keys(localStorage);
}
}
// Usage
Storage.set('user', { name: 'John', age: 30 });
const user = Storage.get('user');
const theme = Storage.get('theme', 'light'); // Default value
if (Storage.has('user')) {
console.log('User data exists');
}
Storage.remove('user');
Storage with Expiration
function setWithExpiry(key, value, ttl) {
const now = new Date();
const item = {
value: value,
expiry: now.getTime() + ttl
};
localStorage.setItem(key, JSON.stringify(item));
}
function getWithExpiry(key) {
const itemStr = localStorage.getItem(key);
if (!itemStr) {
return null;
}
const item = JSON.parse(itemStr);
const now = new Date();
// Check if expired
if (now.getTime() > item.expiry) {
localStorage.removeItem(key);
return null;
}
return item.value;
}
// Store for 1 hour (3600000 ms)
setWithExpiry('authToken', 'abc123xyz', 3600000);
// Retrieve (returns null if expired)
const token = getWithExpiry('authToken');
if (token) {
console.log('Token is valid:', token);
} else {
console.log('Token expired or not found');
}
Storage Events
// Listen for storage changes from other tabs/windows
window.addEventListener('storage', (event) => {
console.log('Storage changed!');
console.log('Key:', event.key);
console.log('Old value:', event.oldValue);
console.log('New value:', event.newValue);
console.log('URL:', event.url);
console.log('Storage area:', event.storageArea);
// Sync UI with changes
if (event.key === 'theme') {
applyTheme(event.newValue);
}
});
// Note: Storage event only fires in OTHER tabs/windows,
// not in the tab that made the change
Real-World Examples
Theme Persistence
class ThemeManager {
static THEME_KEY = 'app-theme';
static getTheme() {
return localStorage.getItem(this.THEME_KEY) || 'light';
}
static setTheme(theme) {
localStorage.setItem(this.THEME_KEY, theme);
this.applyTheme(theme);
}
static applyTheme(theme) {
document.body.className = `theme-${theme}`;
}
static init() {
const theme = this.getTheme();
this.applyTheme(theme);
}
}
// On page load
ThemeManager.init();
// Toggle theme
function toggleTheme() {
const current = ThemeManager.getTheme();
const newTheme = current === 'light' ? 'dark' : 'light';
ThemeManager.setTheme(newTheme);
}
Form Data Persistence
class FormPersistence {
constructor(formId) {
this.form = document.getElementById(formId);
this.storageKey = `form-${formId}`;
this.init();
}
init() {
// Load saved data
this.loadFormData();
// Save on input
this.form.addEventListener('input', () => {
this.saveFormData();
});
// Clear on submit
this.form.addEventListener('submit', () => {
this.clearFormData();
});
}
saveFormData() {
const formData = new FormData(this.form);
const data = Object.fromEntries(formData);
localStorage.setItem(this.storageKey, JSON.stringify(data));
}
loadFormData() {
const saved = localStorage.getItem(this.storageKey);
if (!saved) return;
const data = JSON.parse(saved);
Object.keys(data).forEach(key => {
const input = this.form.elements[key];
if (input) input.value = data[key];
});
}
clearFormData() {
localStorage.removeItem(this.storageKey);
}
}
// Usage
new FormPersistence('contactForm');
Important Considerations
Storage Limits:
- ~5-10MB per origin (varies by browser)
- Synchronous API (blocks main thread)
- String-only storage
Security:
- Not encrypted
- Accessible via JavaScript
- Don't store passwords or tokens
- Vulnerable to XSS attacks
- Shared across all scripts on origin
Best Practices
1. Always use try/catch
try {
localStorage.setItem('key', value);
} catch (error) {
if (error.name === 'QuotaExceededError') {
console.error('Storage quota exceeded');
}
}
2. Validate data before storing
function safeStore(key, value) {
if (!key || value === undefined) return false;
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch {
return false;
}
}
3. Use sessionStorage for temporary data
// Persists only for session
sessionStorage.setItem('tempData', 'value');
// Cleared when tab closes
Key Takeaways
- LocalStorage persists data across browser sessions
- Only stores strings - use JSON for objects
- ~5-10MB storage limit per origin
- Synchronous API - can block main thread
- Not secure - don't store sensitive data
- Always use try/catch for error handling
- Storage events sync data across tabs
- Use sessionStorage for temporary data
- Consider IndexedDB for large datasets