localStorage persists until cleared; sessionStorage clears when the tab ends. Both store UTF-16 strings synchronously on the main thread.
Limits
- Approximate 5 MB per origin depending on browser—handle quota errors.
- Not structured—serialize JSON carefully.
Security
- XSS attacks can exfiltrate storage—never store secrets.
- Prefer HttpOnly cookies for session identifiers.
Alternatives
IndexedDB handles large structured datasets; Cache API pairs with service workers for offline shells.
Performance footnote
Synchronous JSON stringify/parse on huge objects blocks the main thread even if storage persists—still profile.
Typical persistence pattern
const KEY = 'draft:composer';
try {
const raw = localStorage.getItem(KEY);
textarea.value = raw ? JSON.parse(raw).body : '';
} catch (_) { /* corrupt data — reset */ }
function saveDraft() {
localStorage.setItem(KEY, JSON.stringify({ body: textarea.value, ts: Date.now() }));
}
sessionStorage swaps persistence scope to the tab—good for ephemeral wizards.
Storage values are plain strings under the hood.
localStorage.setItem('draft', '{"body":"Hello"}')
localStorage.getItem('draft') // '{"body":"Hello"}'
Important interview questions and answers
- Q: What does progressive enhancement mean in API-driven pages?
A: Core tasks should work with baseline HTML first, then richer APIs enhance experience when supported. - Q: Why is feature detection better than browser sniffing?
A: It checks actual capability, avoids brittle UA assumptions, and degrades gracefully. - Q: What is the first accessibility check before shipping any page?
A: Verify keyboard-only task completion with visible focus and meaningful accessible names.
Pitfall: Never store auth tokens in localStorage on public sites.