JS Sketchbooksee JavaScript think ✏️
← back to phase 7

7.3 — Reading & changing the DOM

You can find any element (7.2). Now you get to touch them — and this is the moment JavaScript stops being a console language: every mutation you make to the tree appears on screen, instantly. Change a text node — the page changes. Add a class — the styling flips. Append a node — content EXISTS where there was none.

Four verbs run the show: read/write text, juggle classes, set attributes, create/remove nodes.

Plus one security landmine (innerHTML) that every beginner must meet before production meets them.

watch it happen
const title = document.querySelector("h1");

console.log(title.textContent);   // read
title.textContent = "Shopping";   // write (safe)

title.classList.add("big");
title.classList.toggle("dark");
title.setAttribute("data-test", "hdr");

const li = document.createElement("li");
li.textContent = "buy tea";
document.querySelector("ul").append(li);

li.remove();

title.textContent reads the words inside the element — a plain string.

the element, live — every edit repaints the page<h1My Listreading: textContent hands you the words inside — just a string
under the hood

The deeper story, with the real names for things — this part is what turns “I saw it” into “I can explain it.”

Precision on the pair everyone confuses: textContent gets/sets the raw text (fast, safe, no parsing); innerHTML gets/sets markup — reading it serializes the subtree to a string, writing it runs the parser and REPLACES all children.

The security rule is one sentence: if a user typed it, it goes in textContent. XSS — script smuggled through markup — is one of the top web vulnerabilities, and test suites (yours, someday) include cases that try exactly that smuggle.

Every mutation also nudges the rendering pipeline — the tree changed, so layout and paint re-run (lesson 7.8 walks that machinery).

Batches of small edits are why real apps repaint smoothly and also why "the element exists but isn't PAINTED yet" moments happen — the root of flaky-test folklore, and of Playwright's auto-waiting cure (11.5).

And a live reference reminder (7.1 + 4.6): hold const el = querySelector(…) once and mutate it all day — every change lands on the real tree through the same arrow. Playwright's locators behave like these references with retry logic bolted on.

your turn

⌨️ implement classList.toggle

The best way to trust a tool is to build its core once. Model an element’s classes as an array and implement the toggle verb — the exact logic behind every dark-mode switch on the web.

requirements:

  • An object el with classes = ["todo"].
  • A function toggle(el, name): if name is present in el.classes, REMOVE it (4.9's filter builds the new array); if absent, ADD it (push). Return nothing — mutate the object (4.6, knowingly!).
  • Toggle "done" (→ added), print the classes joined by a space; toggle "done" again (→ removed), print again.

when you press RUN, the console must show exactly:

todo done
todo

✏️ Quick check 1

A username typed by a user must be shown on the page. Which property do you assign — textContent or innerHTML?

✏️ Quick check 2

el has class "dark". After el.classList.toggle("dark") — is "dark" present? Type yes or no.

✏️ Quick check 3

createElement("li") makes a node. Is it visible on the page before you append it? Type yes or no.

teach it back

🗣️ Now teach it back

Explain to a friend the four DOM mutation verbs (text, classes, attributes, create/remove) — and give them the one-sentence security rule about textContent vs innerHTML, with the reason behind it.

Write it as if your friend is sitting next to you. Saved to your journal — future-you will use these notes to teach others.

a few sentences, minimum — you’ve got this
to remember
textContent = safe literal text (read/write). innerHTML = parsed MARKUP — never feed it user input (XSS).
classList.add/remove/toggle/contains for styling states; setAttribute/getAttribute for attributes (incl. data-test hooks).
create → fill → append to add content (renders on join); remove() to unhook (5.7 sweeps). Every mutation repaints — 7.8 shows how.
next: 7.4 Events →