localStorage API
localStorage provides key-value storage that persists across browser sessions.
Basic Operations
// Set item
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({ name: 'Alice', age: 25 }));
// Get item
const theme = localStorage.getItem('theme'); // 'dark'
const user = JSON.parse(localStorage.getItem('user')); // {name: 'Alice', age: 25}
// Remove item
localStorage.removeItem('theme');
// Clear all
localStorage.clear();
// Get length
const count = localStorage.length;
// Get key by index
const key = localStorage.key(0);
Bracket Notation
// Alternative syntax (like an object)
localStorage['theme'] = 'dark';
const theme = localStorage['theme'];
delete localStorage['theme'];
Storage Event
// Listen for changes (from other tabs/windows)
window.addEventListener('storage', (event) => {
console.log('Key:', event.key);
console.log('Old value:', event.oldValue);
console.log('New value:', event.newValue);
console.log('URL:', event.url);
});
Common Use Cases
// Theme preference
localStorage.setItem('theme', 'dark');
// Form draft
localStorage.setItem('draft-form', JSON.stringify(formData));
// User preferences
localStorage.setItem('preferences', JSON.stringify({
language: 'en',
notifications: true,
fontSize: 14
}));
// Cache API responses
localStorage.setItem('cache-users', JSON.stringify({
data: users,
timestamp: Date.now()
}));
When to Use localStorage
localStorage is useful for persisting non-sensitive data on the client.
Good Use Cases
| Use Case | Why |
|---|---|
| Theme preferences | User preference, not sensitive |
| Language settings | Persistent across sessions |
| Form drafts | Save unsaved work |
| UI state | Sidebar collapsed, grid view |
| Cached data | Reduce API calls |
| Onboarding state | Track tutorial progress |
Bad Use Cases
| Use Case | Why |
|---|---|
| Authentication tokens | Vulnerable to XSS |
| Sensitive data | Visible in DevTools |
| Large data | 5-10MB limit |
| Frequent writes | Synchronous API, blocks main thread |
| Server-side state | Not synchronized with server |
Implementation Example
// Safe localStorage wrapper
const Storage = {
get(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (e) {
console.error('localStorage get error:', e);
return defaultValue;
}
},
set(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (e) {
console.error('localStorage set error:', e);
return false;
}
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
}
};
// Usage
Storage.set('theme', 'dark');
const theme = Storage.get('theme', 'light');
Data Serialization
// Always serialize complex types
localStorage.setItem('user', JSON.stringify(user));
const user = JSON.parse(localStorage.getItem('user'));
// Handle dates
const data = {
createdAt: new Date().toISOString() // Convert to string
};
localStorage.setItem('data', JSON.stringify(data));
const stored = JSON.parse(localStorage.getItem('data'));
stored.createdAt = new Date(stored.createdAt); // Convert back
localStorage Limitations
localStorage has several limitations you need to understand.
Limitations
| Limit | Details |
|---|---|
| Size | ~5-10MB per origin |
| Synchronous | Blocks main thread |
| String only | Must serialize objects |
| No expiration | Manual cleanup required |
| Same origin | Isolated by protocol + domain + port |
| Not accessible in workers | Use IndexedDB instead |
Size Limit
// Check available space
function getStorageSize() {
let total = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
total += localStorage[key].length * 2; // UTF-16
}
}
return total;
}
try {
localStorage.setItem('test', 'x'.repeat(5 * 1024 * 1024));
} catch (e) {
console.error('Storage full:', e.name); // QuotaExceededError
}
Synchronous API
// This blocks the main thread!
localStorage.setItem('large', hugeString);
// Better: Use requestIdleCallback or Web Worker
function saveLargeData(data) {
requestIdleCallback(() => {
localStorage.setItem('large', JSON.stringify(data));
});
}
Cross-Tab Synchronization
// Only syncs via storage event
window.addEventListener('storage', (e) => {
if (e.key === 'user') {
const newUser = JSON.parse(e.newValue);
updateUserUI(newUser);
}
});
// Does NOT sync in same tab!
// Must use custom events or state management
Alternative: IndexedDB
// For larger, async storage
const request = indexedDB.open('MyDB', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
db.createObjectStore('users', { keyPath: 'id' });
};
request.onsuccess = (event) => {
const db = event.target.result;
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
store.add({ id: 1, name: 'Alice' });
};
Performance Tips
// Batch operations
const updates = { theme: 'dark', lang: 'en', notifications: true };
Object.entries(updates).forEach(([key, value]) => {
localStorage.setItem(key, JSON.stringify(value));
});
// Use sessionStorage for temporary data
sessionStorage.setItem('temp', data);
// Use IndexedDB for large datasets
// Use localStorage for small preferences only
Practice Problems
Create a reusable React component implementing Local Storage. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Local Storage using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Local Storage for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What is the approximate size limit of localStorage?
2. Why shouldn't you store auth tokens in localStorage?
3. How do you store an object in localStorage?
4. Does localStorage sync across browser tabs?
Flashcards
Question
What is localStorage?
Click to reveal answer
Answer
Browser storage for key-value pairs that persists across sessions. Limited to ~5-10MB, synchronous, string-only.
Question
Why is localStorage not secure for auth tokens?
Click to reveal answer
Answer
It's accessible to JavaScript, making it vulnerable to XSS attacks that can steal tokens.
Question
How do you store complex objects in localStorage?
Click to reveal answer
Answer
Use JSON.stringify() to serialize and JSON.parse() to deserialize.
Question
What is Local Storage?
Click to reveal answer
Answer
Local Storage is a key concept in frontend development.
Question
When to use Local Storage?
Click to reveal answer
Answer
Use Local Storage when building production systems that require reliability, scalability, and maintainability.
Revision Notes
Key Takeaways
- 1.localStorage persists across browser sessions
- 2.Limited to ~5-10MB and synchronous API
- 3.Always serialize objects with JSON.stringify/parse
- 4.Not secure for sensitive data (vulnerable to XSS)
- 5.Use sessionStorage for temporary data
Interview Tips
- •Know the difference between localStorage and sessionStorage
- •Understand why localStorage is not secure for auth tokens
- •Know the size limitations and alternatives (IndexedDB)
- •Be familiar with the storage event for cross-tab sync
Cheat Sheet
localStorage Cheat Sheet
API Methods:
- setItem(key, value)
- getItem(key)
- removeItem(key)
- clear()
- length
- key(index)
Limitations:
- ~5-10MB per origin
- Synchronous (blocks main thread)
- String only (use JSON)
- No expiration
- Same origin only
Good For:
- Theme preferences
- Language settings
- Form drafts
- UI state
- Cached data
Bad For:
- Auth tokens (XSS risk)
- Sensitive data
- Large datasets
- Server-side state
Best Practice:
Use JSON.stringify/parse for objects