JavaScript / Basic: values and browser foundations / Lesson 6
DOM updates and user events
Connect validated application state to a browser document. Build safe text updates and native controls, then trace event targets, propagation, and listener ownership.
On this page
Lesson goals
- Query and update document nodes safely.
- Trace event target and currentTarget.
- Pair listener setup with cleanup and native semantics.
A document is a live object tree
The DOM represents nodes and their relationships, while HTML supplies element semantics. querySelector returns the first matching element or null, so a missing match needs handling before property access. Run setup after the required markup exists, commonly through a module script whose default execution is deferred relative to parsing. Keep references local to the component that owns them. Updating the DOM changes the displayed interface but does not automatically update a separate application model or persist anything. Decide which state is authoritative and render from it, rather than using arbitrary text on the page as a database.
Create nodes and insert text as text
For a course title supplied by data, create an element and assign textContent. The browser treats angle brackets as text instead of interpreting them as markup. innerHTML parses a string as HTML and therefore crosses a different trust boundary; it is not a convenient interchangeable text setter. The example builds a detached node so it has no dependency on an existing page. In a real interface, append the completed node to the intended container. Keep semantic choices deliberate: a button remains a button, and a list item belongs in an appropriate list.
const item = document.createElement("li");
item.textContent = "<strong>DOM basics</strong>";
console.log(item.textContent);
console.log(item.children.length);
<strong>DOM basics</strong>
0
There is no strong child element. textContent preserves the literal title as data; this snippet requires a DOM-capable browser.
Events describe a path through the tree
An event’s target identifies the originating target, while currentTarget identifies the listener currently handling it. In a bubbling event from a nested span, a listener on the enclosing button sees the span as target and button as currentTarget. Propagation includes capture and, for events that bubble, an upward phase. stopPropagation controls propagation; preventDefault requests cancellation of a cancelable default action. Neither should be added reflexively. Understand whether the task requires suppressing navigation or form submission, and keep keyboard and assistive-technology behavior intact instead of cancelling every event for convenience.
Use a native button and own the listener
Native buttons already provide focusability and activation behavior that a clickable div does not. Register a function value with addEventListener and retain the identity needed to remove it, or use an owned AbortSignal for supported listener cleanup. The deterministic example dispatches a bubbling synthetic event on detached nodes to expose propagation without a network or real user action. Synthetic dispatch is not proof of complete keyboard usability. A real component still needs a visible label, logical focus behavior, and a test of the user task after its state changes.
const button = document.createElement("button");
const label = document.createElement("span");
label.textContent = "Enroll";
button.append(label);
button.addEventListener("click", event => {
console.log(event.target.tagName, event.currentTarget.tagName);
});
label.dispatchEvent(new MouseEvent("click", { bubbles: true }));
SPAN BUTTON
The span starts the event, but the registered listener belongs to the button. No element is inserted into the actual page.
Render meaningful state and release ownership
A disabled control, loading message, and result count should reflect a defined application state rather than independent Boolean flags that can contradict one another. Use event delegation when one stable ancestor owns actions on changing child rows, and resolve the intended action with a bounded closest lookup. Do not trust an arbitrary data attribute as authorization. When a view is destroyed, remove its listeners and references so later events cannot update an obsolete view. Test setup, action, and teardown together; duplicate registration often reveals itself only after opening the same component several times.
Common errors and fixes
A selector result causes a null TypeError
- Why it happens
- The node is absent or setup runs before its markup exists.
- How to fix it
- Check the selector, lifecycle, and required-node contract.
- Prevent it next time
- Test missing markup and normal setup explicitly.
User text becomes executable markup
- Why it happens
- innerHTML is used across an untrusted text boundary.
- How to fix it
- Use textContent or a deliberately reviewed safe rendering policy.
- Prevent it next time
- Keep data and HTML construction interfaces separate.
One click triggers the action twice
- Why it happens
- Repeated setup attaches duplicate listeners.
- How to fix it
- Dispose owned listeners before reinitializing.
- Prevent it next time
- Test mount, unmount, and remount behavior.
Check your understanding
1. A click originates on an icon inside a button. Which target should identify the listener’s button?
Show worked solution
For a listener directly registered on that button, use currentTarget. target may be the icon. For delegated handlers, resolve an allowed closest action element and ensure it belongs to the owning container before using its identifier. Neither identifier establishes server permission.
2. Render a literal course title containing < and >. What is the safe default?
Show worked solution
Create the intended semantic element and assign its textContent to the title. Verify the displayed text and that no additional child markup was created. Use real HTML parsing only when the product intentionally accepts reviewed markup under a separate security policy.
Key takeaways
- DOM APIs belong to the browser host, not the core language.
- Native semantics, text boundaries, and listener lifecycle belong together.