Events, Forms & Browser Storage
The event system
Events are how JavaScript responds to user actions — clicks, key presses, form submissions, scrolling, and more.
Adding event listeners
JavaScript
const button = document.querySelector('#submit');
button.addEventListener('click', (event) => {
console.log('Button clicked!');
console.log('Click coordinates:', event.clientX, event.clientY);
});Always use
addEventListener — not onclick. It lets you attach multiple handlers and remove them later.Common events
| Event | Triggers when... |
|---|---|
click | Element is clicked |
dblclick | Element is double-clicked |
mouseover / mouseout | Mouse enters/leaves element |
keydown / keyup | Key is pressed/released |
input | Input value changes |
change | Input value changes AND loses focus |
submit | Form is submitted |
focus / blur | Element gains/loses focus |
scroll | Element or page is scrolled |
DOMContentLoaded | HTML is fully parsed |
load | Page + all resources are loaded |
The event object
Every event handler receives an event object with useful properties:
JavaScript
document.addEventListener('keydown', (event) => {
console.log(event.key); // "Enter", "Escape", "a", etc.
console.log(event.ctrlKey); // true if Ctrl was held
console.log(event.target); // the element that fired the event
});Preventing default behavior
Some elements have default behaviors (links navigate, forms reload the page). Stop them with
preventDefault():JavaScript
const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
event.preventDefault(); // stop page reload
const formData = new FormData(form);
console.log(formData.get('email'));
});Event delegation
Instead of adding a listener to every list item, add one to the parent:
JavaScript
document.querySelector('.todo-list').addEventListener('click', (event) => {
if (event.target.matches('.delete-btn')) {
const item = event.target.closest('.todo-item');
item.remove();
}
});This works because events bubble up — a click on a button inside a list item also fires on the list item, then the list, then the body, all the way to
document.Event delegation is:
- More efficient (one listener instead of hundreds)
- Works for dynamically added elements
- Used by every major framework internally
Working with forms
Getting form values
JavaScript
const form = document.querySelector('#signup');
form.addEventListener('submit', (event) => {
event.preventDefault();
// Option 1: FormData
const data = new FormData(form);
const email = data.get('email');
const password = data.get('password');
// Option 2: Object from FormData
const values = Object.fromEntries(new FormData(form));
// { email: '...', password: '...' }
});Real-time validation
JavaScript
const emailInput = document.querySelector('#email');
const emailError = document.querySelector('#email-error');
emailInput.addEventListener('input', () => {
if (!emailInput.value.includes('@')) {
emailError.textContent = 'Please enter a valid email';
emailInput.setAttribute('aria-invalid', 'true');
} else {
emailError.textContent = '';
emailInput.removeAttribute('aria-invalid');
}
});localStorage
Persist data across page reloads and browser restarts:
JavaScript
// Save
localStorage.setItem('theme', 'dark');
// Read
const theme = localStorage.getItem('theme'); // "dark"
// Remove
localStorage.removeItem('theme');
// Clear everything
localStorage.clear();Storing objects
localStorage only stores strings. Use JSON for complex data:
JavaScript
const user = { name: 'Alice', preferences: { theme: 'dark' } };
// Save
localStorage.setItem('user', JSON.stringify(user));
// Read
const stored = JSON.parse(localStorage.getItem('user'));
console.log(stored.name); // "Alice"A helper function
JavaScript
function storage(key, value) {
if (value === undefined) {
const item = localStorage.getItem(key);
try { return JSON.parse(item); } catch { return item; }
}
if (value === null) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, JSON.stringify(value));
}
}
storage('user', { name: 'Alice' }); // save
storage('user'); // read → { name: 'Alice' }
storage('user', null); // deletesessionStorage
Same API as localStorage, but data is cleared when the tab closes. Use it for temporary state like form drafts:
JavaScript
const form = document.querySelector('#editor');
form.addEventListener('input', () => {
sessionStorage.setItem('draft', form.querySelector('textarea').value);
});
window.addEventListener('load', () => {
const draft = sessionStorage.getItem('draft');
if (draft) {
form.querySelector('textarea').value = draft;
}
});Cookies vs localStorage vs sessionStorage
| Feature | Cookies | localStorage | sessionStorage |
|---|---|---|---|
| Capacity | ~4KB | ~5-10MB | ~5-10MB |
| Sent to server | Yes (every request) | No | No |
| Expiration | Configurable | Never | Tab close |
| Access | Server + client | Client only | Client only |
Use cookies for auth tokens (httpOnly, secure). Use localStorage for user preferences. Use sessionStorage for temporary data.
Key takeaway
Events drive interactivity — use
addEventListener, understand event delegation, and always preventDefault on forms. For persistence, use localStorage for long-term data and sessionStorage for temporary state. Wrap JSON parsing in try/catch since stored data might be corrupted.