Learning Objectives
- Change content with
textContent, and state precisely why it is the safe default - Explain the injection hazard
innerHTMLcarries with untrusted input - Add, toggle, and remove attributes; write metadata through
dataset - Swap a node with
replaceWithand move one withprepend
Text or markup — decide on purpose
Both of these replace an element's contents. They are not interchangeable:
textContent treats the string as text, tags and all — the <strong> above appears on screen as angle brackets. innerHTML hands the string to the HTML parser, which builds real nodes from it. That is exactly what you want for markup you wrote, and exactly what an attacker wants for markup they wrote.
textContent, always.Attributes, classes, styles
The state-changing tools from step 4 are half of modification in practice. The demo exercises all of them against a single link and paragraph:
The ranking from last step holds under modification: reach for the class first and let CSS carry the design; write style directly only for values computed at runtime — and even then, consider setting a CSS custom property instead, as the demo's third button does.
Structural surgery
Content and state changes leave the tree's shape alone. Two more calls change the shape itself:
The second line is the one that surprises people. There is no copy: a node lives in exactly one place in the tree, so inserting a node that is already attached moves it. Watch item C jump to the front of the list in the demo — one call, no clone, no removal step.
append, prepend, before, after — relocates an already-attached node rather than duplicating it. When you really want a copy, that is what cloneNode is for, next step.Live demo
All four families in one page: text versus HTML, attributes and dataset, classes and styles, and the structural moves. Every action reports to its own live-region log.
Applied: redacted text
A whole feature in one class flip. The stylesheet defines what redaction looks like — .redacted .blk paints marked spans black-on-black — and the script's entire job is classList.add('redacted') and classList.remove('redacted') on the container. This is the flip-a-class principle at full strength: design in CSS, one bit of state in JS.
Next Steps
In Step 6: Creation, we stop editing what the parser built and start growing the tree ourselves:
- Build elements the long way with
createElementandtextContent - Batch a hundred insertions into one with
DocumentFragment - Stamp out repeating structure from a
<template>withcloneNode - Type markup into place with
insertAdjacentHTML