DOM: Document Object Model
The DOM (Document Object Model) is the tree-structured representation of an HTML document that browsers build when they load a page. JavaScript uses the DOM API to read and modify a page's content, structure, and styles.
What Is the DOM
When a browser loads an HTML page, it parses the markup into a tree of objects. That tree is the DOM.
Every HTML element becomes a node in the tree. JavaScript can access and manipulate these nodes through the DOM API.
<html>
<body>
<h1>Hello</h1>
<p>World</p>
</body>
</html>The corresponding DOM tree:
document is the entry point — all DOM operations start there.
Selecting Elements
getElementById
Selects a single element by its id:
const title = document.getElementById('title');querySelector
Selects the first element that matches a CSS selector:
const title = document.querySelector('#title');
const button = document.querySelector('.btn');
const input = document.querySelector('input[type="text"]');querySelectorAll
Selects all matching elements and returns a NodeList:
const items = document.querySelectorAll('.item');
items.forEach(item => {
console.log(item.textContent);
});Other Methods
// by class name (returns HTMLCollection)
document.getElementsByClassName('item');
// by tag name
document.getElementsByTagName('p');In modern code, querySelector and querySelectorAll are the go-to choice — they support the full CSS selector syntax and are more flexible than the older methods.
Modifying the DOM
Reading and Updating Content
const title = document.querySelector('h1');
// read plain text
console.log(title.textContent);
// update plain text
title.textContent = 'Hello World';
// read or update HTML content (including child elements)
title.innerHTML = '<span>Hello</span> World';textContent deals with plain text only. innerHTML can contain HTML markup — but inserting unsanitized user input into innerHTML is an XSS risk, so be careful.
Modifying Attributes
const link = document.querySelector('a');
// read
console.log(link.getAttribute('href'));
// set
link.setAttribute('href', 'https://example.com');
// remove
link.removeAttribute('target');
// direct property access for common attributes
link.href = 'https://example.com';
link.id = 'main-link';Modifying Styles
const box = document.querySelector('.box');
box.style.color = 'red';
box.style.backgroundColor = '#f0f0f0';
box.style.display = 'none';Working with Classes
const button = document.querySelector('.btn');
button.classList.add('active');
button.classList.remove('active');
button.classList.toggle('active'); // adds if absent, removes if present
button.classList.contains('active'); // true / falseManipulating classes is generally better than setting style directly — it keeps styles in CSS where they belong and is easier to maintain.
Adding and Removing Elements
Adding elements:
// create a new element
const newItem = document.createElement('li');
newItem.textContent = 'New item';
// append to the end of a parent
const list = document.querySelector('ul');
list.appendChild(newItem);
// insert at a specific position
list.insertBefore(newItem, list.firstChild);
// flexible insertion with HTML
list.insertAdjacentHTML('beforeend', '<li>New item</li>');Removing elements:
const item = document.querySelector('.item');
// remove the element itself
item.remove();
// or via the parent
item.parentNode.removeChild(item);Event Listeners
addEventListener
The standard way to listen for events:
const button = document.querySelector('button');
button.addEventListener('click', function (event) {
console.log('button clicked');
console.log(event.target); // the element that triggered the event
});Common Events
// mouse events
element.addEventListener('click', handler);
element.addEventListener('dblclick', handler);
element.addEventListener('mouseover', handler);
element.addEventListener('mouseout', handler);
// keyboard events
document.addEventListener('keydown', event => {
console.log(event.key);
});
// form events
input.addEventListener('input', event => {
console.log(event.target.value);
});
form.addEventListener('submit', event => {
event.preventDefault(); // stop the default form submission
console.log('form submitted');
});
// page load
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM ready');
});Removing Event Listeners
To remove a listener, you need a reference to the same function that was added:
function handleClick() {
console.log('clicked');
}
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);Anonymous functions can't be removed — always use a named function if you need to clean up later.
Event Bubbling
When an event fires, it propagates up from the target element through its ancestors. This is called event bubbling:
<div id="parent">
<button id="child">Click</button>
</div>document.getElementById('parent').addEventListener('click', () => {
console.log('parent');
});
document.getElementById('child').addEventListener('click', () => {
console.log('child');
});Clicking the button outputs:
child
parentUse event.stopPropagation() to prevent the event from bubbling further:
document.getElementById('child').addEventListener('click', event => {
event.stopPropagation();
console.log('child only');
});Event Delegation
Event delegation takes advantage of bubbling by listening for events on a parent element instead of attaching individual listeners to each child. It's especially useful for dynamically added elements:
const list = document.querySelector('ul');
list.addEventListener('click', event => {
if (event.target.tagName === 'LI') {
console.log('clicked:', event.target.textContent);
}
});No matter how many <li> elements are added later, they're all covered by this single listener.
Summary
The DOM gives JavaScript the ability to read and control what's on the page:
- Select elements with
querySelector/querySelectorAll - Modify content and appearance with
textContent,innerHTML,classList, andstyle - Add and remove elements with
createElement,appendChild, andremove - Listen for events with
addEventListener— and use bubbling and delegation to keep event handling efficient