Course topics

By WebNest Studio Engineering Team

JavaScript Tutorial

The Document Object Model (DOM)

When a browser loads an HTML page, it doesn't just display the raw markup — it builds an in-memory tree structure called the Document Object Model (DOM). Every tag becomes a node in that tree, and JavaScript can read, modify, add, or remove those nodes at any time, which is what makes web pages interactive rather than static.

The DOM is not part of the JavaScript language itself; it's a browser-provided API. That's why DOM code only runs in a browser environment (not in Node.js by default) and why the global object you interact with is document, which represents the entire loaded page.

Why it matters

The DOM is the page as JavaScript sees it: a tree of objects that can be read and changed. Every interactive feature, from showing an error message to building a list from API data, comes down to selecting elements and modifying them. Frameworks do this for you, but they do it through the same DOM.

The DOM Tree

The DOM models a page as a hierarchy: document is the root, it contains the <html> element, which contains <head> and <body>, and so on down to individual text nodes. Each node has relationships you can traverse programmatically.

  • parentElement / parentNode — the containing element.
  • children — a live collection of child elements (ignores text nodes).
  • childNodes — all child nodes, including text and comment nodes.
  • nextElementSibling / previousElementSibling — adjacent elements at the same level.

Selecting Elements

Modern JavaScript almost always uses document.querySelector() and document.querySelectorAll() because they accept any CSS selector, which is far more flexible than the older getElementById or getElementsByClassName. querySelector returns the first match (or null), while querySelectorAll returns a static NodeList of every match.

  • document.getElementById('id') — fastest, but only matches by id.
  • document.querySelector('.card > h2') — first match for any CSS selector.
  • document.querySelectorAll('li.active') — a NodeList you can loop with forEach.

Creating and Modifying Elements

You build new DOM content with document.createElement(), set its content or attributes, and attach it to the tree with methods like appendChild(), append(), or before()/after(). Existing elements are updated through properties like textContent (plain text, safe from HTML injection), innerHTML (parses a string as markup — use with caution on untrusted input), classList (add/remove/toggle CSS classes), and setAttribute()/getAttribute().

Examples

Selecting an element and updating its content and class

JavaScript
// HTML: <ul id="task-list"><li class="task">Buy milk</li></ul>

const list = document.querySelector('#task-list');
const firstItem = list.querySelector('.task');

firstItem.textContent = 'Buy milk and eggs';
firstItem.classList.add('done');

console.log(firstItem.outerHTML);
Output
<li class="task done">Buy milk and eggs</li>

Creating a new element and appending it to the tree

JavaScript
const list = document.querySelector('#task-list');

const newItem = document.createElement('li');
newItem.textContent = 'Walk the dog';
newItem.classList.add('task');

list.appendChild(newItem);

console.log(list.children.length);
Output
2

Common Mistakes

  • Using innerHTML to insert user-provided text, which can introduce cross-site scripting (XSS) if the text contains HTML/script tags — use textContent for plain text instead.
  • Assuming querySelectorAll() returns an array — it returns a NodeList, which supports forEach but not array methods like map() or filter() without converting it first (Array.from(nodeList)).
  • Running DOM-selecting code before the page has finished parsing, so querySelector returns null for elements that don't exist yet — placing scripts at the end of <body> or using DOMContentLoaded avoids this.
  • Calling getElementsByClassName or getElementsByTagName and forgetting the result is a *live* HTMLCollection, which changes automatically as the DOM changes, unlike the static NodeList from querySelectorAll.

Exercise

Using the DOM, change the text of the heading to DOM practice, add the class highlight to the paragraph, and create a new paragraph containing Added by JavaScript and append it to main.

Expected result: the heading reads DOM practice, and a new paragraph appears at the bottom of the page.

JavaScript · starter code
// The page contains: <main> with an <h1>, a <p> and a <button>

// TODO: change the heading text

// TODO: add the class "highlight" to the existing paragraph

// TODO: create a paragraph with the text "Added by JavaScript" and append it to main
Show hints
  • document.querySelector("h1") returns the first matching element, and textContent sets its text.
  • Create with document.createElement("p"), then attach it with append.
Show solution
JavaScript · solution
// The page contains: <main> with an <h1>, a <p> and a <button>

document.querySelector("h1").textContent = "DOM practice";

document.querySelector("p").classList.add("highlight");

const paragraph = document.createElement("p");
paragraph.textContent = "Added by JavaScript";
document.querySelector("main").append(paragraph);

Quick quiz

1. What does document.querySelectorAll(".item") return?

  • A. The first matching element
  • B. An array
  • C. A string of HTML
  • D. A NodeList of every matching element
Show answer

D. A NodeList can be looped over with forEach, but it is not an array.

2. Why is textContent safer than innerHTML for showing text typed by a user?

  • A. It treats the value as plain text, so any markup in it is not executed
  • B. It is faster to type
  • C. It supports more browsers
  • D. innerHTML cannot show text
Show answer

A. Putting untrusted input into innerHTML can run an attacker's script: cross-site scripting.

3. What does document.querySelector("#menu") return when no element matches?

  • A. undefined
  • B. null
  • C. It throws an error
  • D. An empty NodeList
Show answer

B. Using the result without checking is the cause of "cannot read properties of null".

Interview questions

What is the DOM?

Show answer

The Document Object Model is the browser's representation of a page as a tree of objects, one for each element, attribute and piece of text. It is built from the HTML when the page loads. JavaScript uses the DOM API to find nodes, read and change their content, attributes and styles, add and remove nodes, and listen for events. Changing the DOM changes what is shown on screen.

What is the difference between innerHTML, textContent and innerText?

Show answer

innerHTML reads or sets the content as HTML, so tags in the string become elements; it must never be given untrusted input. textContent reads or sets the raw text of the node and all its descendants, treating everything as text. innerText returns only the text that is visibly rendered, taking CSS into account, which makes it slower. For plain text, textContent is the usual choice.

Key Points to Remember

  • The DOM is a tree representation of the page that JavaScript can read and mutate at runtime.
  • querySelector/querySelectorAll accept full CSS selectors and are the modern default for finding elements.
  • Use textContent for safe plain text and innerHTML only for trusted markup.
  • New elements are built with createElement() and attached with methods like appendChild().

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Shows a live preview of your HTML, CSS and JavaScript. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering