WIP · JavaScript · Lesson 003
Selectors, Buttons and the DOM
Chapter III · Finding things on the page without accidentally summoning the wrong button
Archive Summary
This lesson moves from the browser console into the web page itself. JavaScript can find HTML elements, listen for clicks, and change what the visitor sees. The important word is find: if JavaScript finds the wrong thing, it may still work perfectly while doing the wrong job.
We begin with selectors, then connect one button to one panel. After that, Michael selects a button too broadly, Gidza appears in the wrong procedural location, and De la Vega explains why the machine was technically obedient.
“A selector does not find what you meant. It finds what you asked for.” — De la Vega’s School of Code
1. What is the DOM?
The DOM is the browser’s live model of the HTML page. When JavaScript uses
document, it is talking to the page that the browser has built
from the HTML.
console.log(document);
In beginner terms: document is the whole page. Selectors are
the instructions we give JavaScript when we want it to find one specific
part of that page.
“HTML is the archive shelf. The DOM is the shelf after the browser has opened the room.” — Lesson 003 field note
2. What is a selector?
A selector is a small text pattern that points to an element on the page.
JavaScript can use CSS-style selectors with querySelector.
document.querySelector("button");
document.querySelector(".article-action");
document.querySelector("#paper-title");
document.querySelector("[data-copy-link]");
<button> element.
Useful, but often too broad.
article-action.
Good for styling. Risky as a JavaScript target.
paper-title.
An id should be unique on the page.
data-copy-link.
A clean handle for JavaScript behaviour.
3. querySelector()
querySelector() finds the first element that matches the selector.
If several elements match, JavaScript does not ask which one you meant. It
takes the first one and continues with bureaucratic confidence.
const title = document.querySelector("#paper-title");
console.log(title);
This finds the page title element because #paper-title points to
the element with id="paper-title".
“First match means first match. Not best match. Not emotionally correct match.” — De la Vega correction note
4. Data attributes as JavaScript handles
A class usually describes how something looks. A data-* attribute
can describe what JavaScript should use it for.
<button type="button" class="article-action" data-gidza-report>
OPEN GIDZA REPORT
</button>
5. First tiny page reaction
Here is a small HTML example: one button and one hidden panel.
<button type="button" data-gidza-button>
Open Gidza report
</button>
<div data-gidza-panel hidden>
Another job for me!! I am not a robot!!
</div>
Now JavaScript finds both pieces and connects them.
const button = document.querySelector("[data-gidza-button]");
const panel = document.querySelector("[data-gidza-panel]");
button.addEventListener("click", () => {
panel.hidden = !panel.hidden;
});
In plain language: find the button, find the panel, and when the button is clicked, change the panel from hidden to visible or from visible to hidden.
“Click button. Gidza appears. Gidza complains. Education has occurred.” — Lesson 003 field note
6. addEventListener()
addEventListener() tells JavaScript to wait for something to
happen. In this lesson, the event is a click.
button.addEventListener("click", () => {
console.log("Button clicked.");
});
querySelector.
The listener must be attached to the correct element.
7. Michael Horror Example: The Wrong Button Incident
Michael has three article action buttons. They share the same visual class because they should look related.
<div class="article-actions">
<button type="button" class="article-action" data-copy-link>
COPY LINK
</button>
<button type="button" class="article-action" onclick="window.print()">
PRINT LESSON
</button>
<button type="button" class="article-action" data-gidza-report>
OPEN GIDZA REPORT
</button>
</div>
<div data-gidza-panel hidden>
Another job for me!! I am not a robot!!
</div>
Michael writes:
const button = document.querySelector(".article-action");
const panel = document.querySelector("[data-gidza-panel]");
button.addEventListener("click", () => {
panel.hidden = !panel.hidden;
});
Michael expected:
Click OPEN GIDZA REPORT
Gidza panel opens
JavaScript produced:
Click COPY LINK
Gidza panel opens
Click OPEN GIDZA REPORT
Nothing happens
JavaScript did exactly what it was asked to do. It found the first element
with the class article-action. That was the COPY LINK button,
not the Gidza button.
“He selected a button. Unfortunately, not the button.” — Gidza review
Try the wrong button incident
Awaiting selector betrayal...
8. De la Vega Correction
The correction is to select the behaviour hook, not the shared design class.
const button = document.querySelector("[data-gidza-report]");
const panel = document.querySelector("[data-gidza-panel]");
button.addEventListener("click", () => {
panel.hidden = !panel.hidden;
});
Now JavaScript finds the exact button marked with data-gidza-report.
The class can continue styling all action buttons, while the data attribute
quietly tells JavaScript which button has the Gidza job.
“Classes may dress the staff. Data attributes identify the guilty department.” — De la Vega correction note
9. querySelectorAll()
Sometimes we do want every matching element, not just the first one. For that,
use querySelectorAll().
const buttons = document.querySelectorAll(".article-action");
console.log(buttons);
This returns a list-like collection of all matching elements. We do not need to master loops yet, but it is important to know the difference.
10. Safety check: what if nothing is found?
If JavaScript cannot find the element, querySelector() returns
null. A common beginner error is trying to add a click listener
to nothing.
const button = document.querySelector("[data-missing-button]");
button.addEventListener("click", () => {
console.log("This will not work.");
});
Possible console complaint:
Cannot read properties of null
Safer version:
const button = document.querySelector("[data-gidza-report]");
if (button !== null) {
button.addEventListener("click", () => {
console.log("Gidza report requested.");
});
}
“Before speaking to the button, confirm the button exists.” — Lesson 003 field note
11. Tiny Exercise
Look at the HTML below. Which selector should open the Gidza panel, and which selector is too broad?
<button class="article-action" data-copy-link>COPY LINK</button>
<button class="article-action" data-gidza-report>OPEN GIDZA REPORT</button>
<div data-gidza-panel hidden>
Gidza has been summoned against policy.
</div>
// Too broad?
document.querySelector(".article-action");
// More precise?
document.querySelector("[data-gidza-report]");
“If several elements share a class, do not use that class as if it identifies one exact job.” — De la Vega selector note