Skip to lesson content
Web Technologies › Level 16
LEVEL 16 · BROWSER

DOM and Browser Programming

Inspect the document tree and make targeted, understandable page updates.

🌳 DOM tree🔎 Selection🛠️ Live updates🧪 Lab + MCQs
01

Learning Objectives

Level 15 transformed a workshop collection as data. This lesson connects that data to the browser’s document tree. You will select elements, read properties, change text, create and remove nodes, apply classes and inspect the current result.

Our task is a local workshop-card editor. Its controls update a small preview region without replacing the site header, sidebar or footer. You will distinguish a source HTML file from the live DOM and explain why a page update disappears after a reload unless a deliberate persistence mechanism exists.

Tree

Identify elements, text nodes and relationships.

Selection

Choose selectors and handle a missing match.

Updates

Use targeted text, property and node operations.

Usability

Keep labels, status and focus meaningful after changes.

02

DOM — The Browser’s Document Tree

The Document Object Model represents the document as objects that scripts can inspect and change. The browser parses HTML into a tree, and scripts can then change that live tree. The current DOM can differ from the text originally downloaded in the HTML file.

The document contains elements, text and other node kinds. An article is an element node; the words inside its heading belong to a text node. Whitespace between elements can also be a text node, which matters when traversing all child nodes.

A DOM update does not rewrite your GitHub file. Changing a title with textContent affects this document instance. Reloading normally starts again from the delivered page and its initialization code.

Workshop preview tree
document

The loaded page document.

ul preview

The collection container.

li → article

One workshop card.

h4 + p

Its title and explanatory text.

03

document, window and the Browser Environment

Document is the main entry point for the page’s document tree. Window exposes the browser window’s environment, including facilities such as timers and viewport information. These are browser APIs, not keywords built into the JavaScript language.

A pure function can calculate a record without document. A rendering function needs the document or a node to update. Keeping those responsibilities separate makes it easier to inspect a calculation without confusing it with layout behavior.

The DOM tree and the rendered layout are related but different. An element can exist in the DOM while being hidden from rendering. Counting element nodes does not prove the content is readable or operable.

const preview = document.getElementById("preview");
console.log(window.innerWidth);
console.log(preview !== null);

Window.innerWidth is viewport information, not the width of every content panel. Use the appropriate element measurement when the question concerns a card or container.

04

Initialize After the Required Elements Exist

A selector can return no match because the element is absent or because the script ran before parsing reached it. An external classic script with defer can run after parsing. DOMContentLoaded is another useful initialization point when you need the parsed document.

For a script that might be loaded after DOMContentLoaded has already fired, checking document.readyState avoids registering a listener for an event that will not happen again. Keep initialization idempotent if the application can call it more than once, so listeners are not duplicated.

This course’s lesson scripts are included in the page and initialize once on DOMContentLoaded. A component loader with a different lifecycle would need to account for its own insertion and cleanup.

function initPreview() {
  const preview = document.getElementById("preview");
  if (!preview) return;
  // Set up this preview once.
}
if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", initPreview, { once: true });
} else {
  initPreview();
}
05

Select One Element and Check the Result

GetElementById looks up an ID string and returns the matching element or null. It does not take a CSS # prefix. QuerySelector takes a CSS selector and returns the first matching element or null. A malformed selector can throw a SyntaxError rather than merely return no match.

IDs should be unique within the document. A first-match selector is not a repair for duplicate IDs. Scope a query to the preview element when the action should affect its cards rather than unrelated cards in the lesson or sidebar.

Do not concatenate arbitrary user input into a selector and assume the resulting selector is valid. Generated IDs and controlled selectors simplify this lab. For an actual arbitrary identifier in a selector, use appropriate escaping such as CSS.escape.

const preview = document.getElementById("preview");
const firstTitle = preview?.querySelector(".card-title");
if (firstTitle) {
  firstTitle.textContent = "HTML Workshop";
}

Optional chaining avoids a property access on null here. It does not prove a required preview was successfully loaded; a real initialization failure should still be diagnosed rather than silently ignored everywhere.

06

Select Many — Static and Live Collections

QuerySelectorAll returns a static NodeList of matching elements. Its membership is a snapshot from the query time. If another card is inserted later, query again to obtain a list that includes it. The referenced elements themselves can still change; static does not mean frozen nodes.

Some other collections are live, such as an element’s children HTMLCollection. Its membership changes as the DOM changes. Iterating a live collection while removing elements can skip items if the indexes shift.

A NodeList is not an ordinary array with every array method. You can iterate it or convert it with Array.from when you want array operations. Choose a fresh query for an inspector that should reflect the current preview.

const before = preview.querySelectorAll(".card");
// Insert another card here.
const after = preview.querySelectorAll(".card");
console.log(before.length, after.length);
const titles = Array.from(after, card =>
  card.querySelector(".card-title").textContent
);

The lab’s inspector reads the current preview after each operation. It does not reuse the initialization query and then pretend that it counts newly added cards.

07

textContent — Update Text Deliberately

TextContent reads or sets textual content. Setting it on an element replaces that element’s children with text, so choose the intended leaf element. Updating the title heading preserves the rest of the article; setting the whole article’s textContent would remove its note and badge.

InnerHTML parses markup. It is useful in carefully controlled situations, but placing untrusted text into it can create an injection risk. This lab uses createElement and textContent so a supplied label such as <strong>HTML</strong> remains literal text.

TextContent is not a measurement of what is visually readable. It can include text from hidden descendants. InnerText has rendering-aware behavior and different costs; choose the property that matches the task.

const title = card.querySelector(".card-title");
title.textContent = userSuppliedTitle;
// Literal text, not parsed HTML markup.

The preview editor changes a title and note separately. Its inspectable snapshot shows the same literal text instead of interpreting angle brackets as an instruction to build new elements.

08

Attributes and Properties — Related, Not Identical

An HTML attribute is part of the element’s attribute representation. A DOM property can expose current state. Some properties reflect attributes closely; others have distinct current and default states. Input.value is a common example: typing changes the current value without necessarily changing the value attribute.

A boolean attribute such as disabled depends on its presence. Disabled="false" still supplies the disabled attribute. Use button.disabled = false or removeAttribute("disabled") when you intend to enable the button.

Set attributes such as aria-pressed to the strings "true" or "false" according to the actual toggle state. Adding ARIA does not create the behavior it describes; the handler still has to perform the action.

button.disabled = cards.length === 0;
button.setAttribute("aria-pressed", highlighted ? "true" : "false");
console.log(input.value); // current user entry
console.log(input.getAttribute("value")); // attribute representation

In this lab, edit/remove/highlight controls are disabled when no card exists. The highlight toggle’s aria-pressed state is synchronized with the selected card’s class.

09

dataset — Small Data Attributes

Data attributes can associate a small identifier with an element. Data-card-id is exposed as element.dataset.cardId. Dataset values are strings; storing data-count="3" does not make dataset.count a Number automatically.

Use a stable generated ID to match a select option with a preview card. A display title may change, contain spaces or be duplicated, so it is a poor identity key. Do not put private secrets in data attributes; they are visible in the client document.

A dataset is not a database or proof of trustworthy input. The lab generates its own card IDs and restricts actions to the preview’s current cards.

card.dataset.cardId = "card-1";
console.log(card.dataset.cardId); // "card-1"
// HTML representation: data-card-id="card-1"

When a title is edited, the card keeps its ID. Adding two cards with the same title is allowed; their generated IDs remain different.

10

classList and Styles — Keep Presentation in CSS

ClassList.add, remove and toggle update class tokens without replacing every existing class. A two-argument toggle can apply a boolean state deterministically. This is useful for a highlighted card whose appearance is already defined in CSS.

Element.style exposes inline declarations. It does not report every declaration from stylesheets. GetComputedStyle reads resolved style information for an element; its result should not be confused with the original stylesheet text.

A meaningful state needs more than color. The lab’s highlight state changes the border and adds a visible “Highlighted” badge while updating the toggle’s pressed state. Selection and highlighting are separate concepts.

card.classList.toggle("is-highlighted", highlighted);
badge.hidden = !highlighted;
// CSS controls the actual border and badge presentation.
const resolvedColor = getComputedStyle(card).color;

Avoid continuously replacing style strings for every small state change. A scoped class is easier to review and does not accidentally remove unrelated inline properties.

11

Create, Populate and Insert Nodes

CreateElement makes an element that is initially disconnected from the document. Set its text and attributes, assemble its children, then insert it into the intended container. Creation by itself does not display anything on the page.

Append can append nodes or strings; appendChild accepts a node. Appending an already connected node moves that node rather than cloning it. CloneNode creates a copy under its rules, but does not automatically copy event listeners registered with addEventListener.

A DocumentFragment can group nodes before insertion. It is a useful organization tool, not a guarantee that any particular application becomes faster. Match the approach to the number of updates and the code’s clarity.

const item = document.createElement("li");
const article = document.createElement("article");
const title = document.createElement("h4");
title.className = "card-title";
title.textContent = "HTML Workshop";
article.append(title);
item.append(article);
preview.append(item);

The lab creates a list item containing an article, heading, note and badge. It sets the user’s text as textContent before insertion and limits the preview to six cards.

12

Traverse the Tree — Elements or All Nodes?

ParentElement, children and nextElementSibling work with element relationships. ChildNodes and nextSibling can also include text or comment nodes. A formatting newline can therefore be the next sibling even when the next visible card is an element.

Closest searches the element itself and then its ancestors for a matching selector. QuerySelector searches matching descendants. These directions matter when locating the containing card or a title inside it.

Keep traversal scoped and purposeful. A handler should not climb until it finds any article in the entire document if the intended card belongs only to the preview.

const title = card.querySelector(".card-title");
const owner = title.closest("article");
console.log(owner === card); // true in this structure
console.log(preview.children.length); // current element children

The lab’s empty-state paragraph is outside the list. That keeps the list’s element children aligned with its actual card count.

13

Remove and Replace — Understand What Survives

Element.remove disconnects that element from its parent. A JavaScript variable can still refer to the detached object afterward. Removing an element from the document does not automatically erase every reference or listener associated with it.

ReplaceChildren replaces a container’s children with the supplied nodes or text. It is useful for a deliberate reset, but replacing a subtree can remove focused controls, selection state and node-specific listeners. A targeted update often preserves more useful state.

The editor adds, edits and removes preview nodes directly. Reset intentionally rebuilds only the preview cards and selection options. The input controls, status region, lesson content and global shell remain in place.

const cardItem = card.closest("li");
cardItem.remove();
// The item is detached; a variable may still refer to it.

preview.replaceChildren(); // clear only this container

When the selected card is removed, select the next remaining card, or the previous one when appropriate. If none remain, show an empty message and focus the title input so a new card can be created.

14

DOM Changes, Focus and Feedback

A successful DOM mutation should remain understandable to the person using the page. Use labeled native controls, a concise status region and a meaningful focus path. An article is content; it does not need to become a pretend button just to select it.

Do not move focus after every ordinary text update. Save and highlight keep the action control available. Removing the last card disables actions that require a selected card, so the lab deliberately returns focus to the editable title field.

A role="status" region announces concise updates in supporting assistive technology. Replacing an entire live preview on every keystroke can be noisy. The editor runs on explicit buttons and announces one outcome rather than broadcasting the full DOM snapshot.

status.textContent = "Card removed. Two cards remain.";
if (remainingCards.length > 0) {
  selector.focus();
} else {
  titleInput.focus();
}

Native keyboard and assistive-technology behavior should still be tested in a browser. A correct attribute or DOM snapshot alone is not a full accessibility result. Event propagation and form validation are developed further in Level 17.

15

Browser Measurements and Persistence

GetBoundingClientRect reports an element’s box relative to the viewport. Scrolling can change its reported position. Window.innerWidth describes the viewport; scrollHeight and clientHeight answer different questions about content and visible area. Do not infer a card’s layout from its title length alone.

Reading layout after frequent writes can have a performance cost. Prefer a clear update followed by the measurements you actually need, rather than repeatedly alternating tiny writes and reads inside a large loop.

A local DOM editor does not save to GitHub or a server. Storage APIs offer deliberate client persistence, but storage can be unavailable and stored text needs validation when read back. This lab intentionally resets its preview on page reload; only the course’s completion marker uses the established local storage behavior.

const box = card.getBoundingClientRect();
console.log(box.width, box.height);
console.log(box.top); // viewport-relative position

Use the browser’s Elements and accessibility inspection tools to review the live structure, computed styles and properties. View Source usually shows delivered HTML rather than every subsequent DOM mutation.

16

Premium Visualizer — A DOM Update Journey

Follow a fixed card-creation example through selection, creation, population, insertion and inspection. Use the approved timeline and playback controls. This visualizer explains the operations; the live lab below performs actual preview updates.

DOM UPDATE TRACE
Step 1 of 5
STEP 01

Find the intended preview region

Use a fixed ID and check that the preview exists.

document.getElementById("preview")

What is happening?

A null result must be handled. The operation stays scoped to the preview, not the global page shell.

17

Premium Interactive — Live DOM Card Editor

Select a card, edit its title and note, then save the text. Add a new card from the fields, toggle its highlight or remove the selected card. The preview uses actual list items and articles built with DOM methods; the inspector reads their current text and class state.

Titles must contain 1–60 characters after trimming; notes may be blank and are limited to 180 characters. The preview holds at most six cards. Duplicate titles are allowed because identity comes from generated IDs. Angle brackets remain literal text.

Remove all cards to test the empty state, then add one again. Reset restores the three starting cards and their unhighlighted state. Changes are local to this page visit and are not saved to the website repository.

Preview is ready.

Live preview

    Last operation

    Current DOM snapshot

    18

    Debugging — Structure, Timing and Current State

    Selection

    Check IDs, selectors, scope and null results.

    Timing

    Check whether the required nodes exist at initialization.

    Text

    Inspect the leaf updated and whether markup was unintentionally parsed.

    State

    Check disabled controls, pressed state, focus and current counts.

    If an added card is absent from a saved NodeList, perform a fresh query before assuming append failed. If editing deletes the note, inspect whether textContent was assigned to the entire article. If disabled="false" leaves a button disabled, use the boolean property or remove the attribute.

    If a reset causes an action to fire twice, inspect duplicate listener registration. If removing a card loses the keyboard path, decide which surviving control should receive focus. If the inspector reports data but the card is invisible, inspect CSS and rendering rather than claiming the DOM count proves visual success.

    Use a minimal failing sequence: add one card, edit its title, toggle highlight, remove it, then reset. Confirm each operation changes only the intended preview and that the source page remains intact.

    19

    Interview Questions — Flip to Explain

    QUESTION

    Does a DOM update rewrite the original HTML file?

    Click or press Enter to explain
    ANSWER

    No. It changes the live document instance. Repository or server persistence requires a separate deliberate mechanism.

    QUESTION

    What does querySelector return when no element matches?

    Click or press Enter to explain
    ANSWER

    Null. Check it before accessing properties; an invalid selector can instead throw a SyntaxError.

    QUESTION

    Is querySelectorAll a live collection?

    Click or press Enter to explain
    ANSWER

    No. Its NodeList membership is static. Query again to include newly inserted matching elements.

    QUESTION

    Why use textContent for a user-provided title?

    Click or press Enter to explain
    ANSWER

    It supplies literal text rather than parsing markup. Target the heading so unrelated article children survive.

    QUESTION

    Does disabled="false" enable a button?

    Click or press Enter to explain
    ANSWER

    No. A boolean disabled attribute is active when present. Set the disabled property to false or remove the attribute.

    QUESTION

    What does append do with a node already in the document?

    Click or press Enter to explain
    ANSWER

    It moves that node to the new location rather than automatically cloning it.

    QUESTION

    Does remove erase every JavaScript reference?

    Click or press Enter to explain
    ANSWER

    No. The node is disconnected, but existing references can still point to that object.

    QUESTION

    What should happen after removing the last selected card?

    Click or press Enter to explain
    ANSWER

    Show a clear empty state, disable actions requiring a selection and preserve a usable focus path, such as the title field for adding a card.

    20

    MCQ Practice — Explain the Live Document

    PRACTICE

    1. Which object is the main entry point for this page’s document tree?

    PRACTICE

    2. What argument belongs in getElementById for id="preview"?

    PRACTICE

    3. What does a valid querySelector return with no match?

    PRACTICE

    4. Which collection has static query-time membership?

    PRACTICE

    5. Which property supplies literal user text to a title?

    PRACTICE

    6. What happens when textContent is set on an entire article?

    PRACTICE

    7. How do you enable a disabled native button?

    PRACTICE

    8. What type is dataset.cardId?

    PRACTICE

    9. Which method changes one class token without replacing all class names?

    PRACTICE

    10. What does appending an already connected node normally do?

    PRACTICE

    11. What does element.remove do?

    PRACTICE

    12. Which statement fits the live editor’s persistence?

    21

    Extra Practice — Check Specific DOM Operations

    Literal markup

    Save a title containing tags as typed text. Expected: the brackets appear literally; no nested strong element is created.

    Insertion

    Add one card to the three starting cards. Expected: four list items and a unique generated ID.

    Highlight

    Toggle twice. Expected: class and badge turn on, then off; aria-pressed follows the selected state.

    Leaf update

    Edit a heading. Expected: its note and generated ID remain available.

    Empty state

    Remove every card. Expected: count zero, clear empty message and disabled selection actions.

    Rebuild

    Reset after editing and removing. Expected: three original unhighlighted cards.

    Static query

    Save querySelectorAll results, insert a card, then query again. Expected: saved membership stays unchanged; fresh membership includes the addition.

    Keyboard path

    Use Tab and native buttons to remove the last card, then add one. Expected: focus remains on a useful surviving control.

    22

    Quick Revision

    DOM: The live document tree can differ from source HTML.
    Select: Use the correct selector API and check a missing match.
    Collections: Distinguish static snapshots from live membership.
    Text: Update a leaf with literal textContent.
    Properties: Current state and attribute representation can differ.
    Identity: Use generated IDs rather than editable titles.
    Classes: Synchronize CSS state and meaningful feedback.
    Insert: Creation and connection are separate operations.
    Remove: Detachment does not erase every reference.
    Review: Test focus, status, rendering and persistence expectations.
    23

    Glossary — Flip to Learn

    TERM

    DOM

    Click to see meaning
    DEFINITION

    DOM

    The object representation and APIs for the document tree.

    TERM

    Node

    Click to see meaning
    DEFINITION

    Node

    An object in the document tree, such as an element or text node.

    TERM

    Element

    Click to see meaning
    DEFINITION

    Element

    A node representing an HTML or other markup element.

    TERM

    Selector

    Click to see meaning
    DEFINITION

    Selector

    A pattern used to identify matching elements.

    TERM

    NodeList

    Click to see meaning
    DEFINITION

    NodeList

    A collection of nodes; querySelectorAll supplies a static one.

    TERM

    Attribute

    Click to see meaning
    DEFINITION

    Attribute

    A named value in an element’s attribute representation.

    TERM

    Property

    Click to see meaning
    DEFINITION

    Property

    A field on a DOM object that may expose current state.

    TERM

    Dataset

    Click to see meaning
    DEFINITION

    Dataset

    The string-valued interface to an element’s data attributes.

    TERM

    Detached node

    Click to see meaning
    DEFINITION

    Detached node

    A node disconnected from the document or its previous parent.

    TERM

    Focus

    Click to see meaning
    DEFINITION

    Focus

    The current target for keyboard interaction in the document.

    24

    Final Challenge — A Scoped Preview Editor

    Build a labeled card editor with a list preview. Generate stable IDs, set user text with textContent, and create semantic list items containing articles. Add, edit, highlight and remove cards without replacing unrelated page content.

    Keep a six-card teaching limit, title and note limits, synchronized disabled/pressed states and a clear zero-card outcome. Target the title and note for edits. Use a fresh query for the inspector. Announce a concise result and choose a useful focus target when removing the last selected card.

    Test literal angle brackets, duplicate titles, a rejected blank title, six-card capacity, removal to zero, addition after zero and reset. Inspect node structure, visible text, class state and keyboard behavior. State explicitly whether the data persists after reload.

    Success criterion: explain each update in terms of selection, node/property changes and connection to the live document. Level 17 will deepen events, propagation and form validation.

    25

    Level 16 Complete?

    Before marking complete, create a scoped preview update, distinguish text from markup, handle missing selections and demonstrate the empty-state keyboard path. Completion is a local study marker rather than an assessment score.