WIP · JavaScript · Lesson 004
classList, Hidden Panels and the Dot That Lied
Chapter IV · Changing visual state without accidentally filing punctuation as a class name
Archive Summary
This lesson continues from selectors and buttons into visible page state. JavaScript can hide, show, decorate and mark elements by changing their attributes and classes. The goal is not merely to make something appear. The goal is to make the page state clear, controlled and readable.
We begin with hidden, then move to classList.
Michael then includes a dot where JavaScript did not request one, the CSS
waits in silence, and De la Vega explains the difference between selecting
a class and assigning a class.
“A dot is not decoration when the machine is reading it.” — De la Vega’s School of Code
1. What is visual state?
Visual state means the current visible condition of something on the page: open or closed, active or inactive, selected or not selected, warning or normal.
<div data-gidza-panel hidden>
Another job for me!! I am not a robot!!
</div>
In this example, the panel has a state already: it is hidden. JavaScript can change that state when a button is clicked.
“State is what the page currently believes about itself.” — Lesson 004 field note
2. The hidden attribute
The hidden attribute is a simple HTML way to say that an element
should not be shown.
<section data-gidza-panel hidden>
Gidza report unavailable until someone accepts responsibility.
</section>
JavaScript can read and change that property directly.
const panel = document.querySelector("[data-gidza-panel]");
panel.hidden = false;
Setting panel.hidden = false removes the hidden state. Setting
panel.hidden = true hides the panel again.
3. Toggling hidden
A common pattern is to switch between hidden and visible each time the button is clicked.
const button = document.querySelector("[data-gidza-report]");
const panel = document.querySelector("[data-gidza-panel]");
button.addEventListener("click", () => {
panel.hidden = !panel.hidden;
});
The ! means “not”. So !panel.hidden means “the opposite
of the current hidden value”.
“The exclamation mark is a tiny Njet.” — Gidza operator note
4. What is classList?
classList lets JavaScript add, remove and toggle CSS classes on an
element. This is useful when the element should change appearance.
const panel = document.querySelector("[data-gidza-panel]");
panel.classList.add("is-open");
panel.classList.remove("is-open");
panel.classList.toggle("is-open");
In plain language: add the class, remove the class, or switch it on/off.
5. CSS selector vs JavaScript class name
CSS often uses a dot when it selects a class.
.is-open {
border-color: var(--amber);
}
But JavaScript classList wants the class name itself, without the dot.
panel.classList.add("is-open");
“Use the dot when selecting a class in CSS. Do not pack the dot into the class name.” — De la Vega correction note
6. Michael Horror Example: The Dot That Lied
Michael wants to open a Gidza panel by adding the class is-open.
The CSS is waiting for that exact class.
.gidza-panel {
display: none;
}
.gidza-panel.is-open {
display: block;
}
Michael writes:
const button = document.querySelector("[data-gidza-report]");
const panel = document.querySelector("[data-gidza-panel]");
button.addEventListener("click", () => {
panel.classList.toggle(".is-open");
});
Michael expected:
Click OPEN GIDZA REPORT
Gidza panel opens
JavaScript produced:
Click OPEN GIDZA REPORT
Nothing visible happens
JavaScript did not add is-open. It added a class name containing
the dot: .is-open. The CSS was waiting for is-open, so the
panel stayed hidden.
“He included the dot. The dot was not authorized.” — Gidza review
7. De la Vega Correction
const button = document.querySelector("[data-gidza-report]");
const panel = document.querySelector("[data-gidza-panel]");
button.addEventListener("click", () => {
panel.classList.toggle("is-open");
});
Try the dot incident
Awaiting unauthorized punctuation...
Now JavaScript toggles the class is-open. The CSS selector
.gidza-panel.is-open can match the element, and the panel opens.
“The selector wears the dot. The class name does not.” — Lesson 004 field note
8. Combining hidden and classList
Sometimes hidden controls whether the element exists visually, while
a class controls how it looks when visible.
button.addEventListener("click", () => {
const isOpening = panel.hidden;
panel.hidden = !isOpening;
panel.classList.toggle("is-open", isOpening);
});
Here isOpening remembers whether the panel was hidden before the click.
If it was hidden, we show it and add is-open. If it was already open,
we hide it and remove is-open.
“Remember the old state before you change it, unless you enjoy paperwork without a timeline.” — De la Vega field note
9. aria-expanded
When a button opens or closes something, it is polite to update
aria-expanded. This helps assistive technology understand whether
the controlled panel is open.
<button
type="button"
data-gidza-report
aria-controls="gidza-report-panel"
aria-expanded="false">
Open Gidza report
</button>
<section id="gidza-report-panel" data-gidza-panel hidden>
Another job for me!! I am not a robot!!
</section>
button.addEventListener("click", () => {
const isOpening = panel.hidden;
panel.hidden = !isOpening;
panel.classList.toggle("is-open", isOpening);
button.setAttribute("aria-expanded", String(isOpening));
});
String(isOpening) turns true or false into text,
because HTML attributes are written as text.
10. Safety check: only continue if both elements exist
Lesson 003 checked whether one selected element existed. Now we check both the button and the panel before connecting them.
const button = document.querySelector("[data-gidza-report]");
const panel = document.querySelector("[data-gidza-panel]");
if (button !== null && panel !== null) {
button.addEventListener("click", () => {
const isOpening = panel.hidden;
panel.hidden = !isOpening;
panel.classList.toggle("is-open", isOpening);
button.setAttribute("aria-expanded", String(isOpening));
});
}
The && means “and”. This says: only attach the click listener if
both the button and the panel were found.
“Before opening a department, confirm both door and department exist.” — Gidza procedural note
11. Tiny Exercise
Look at the code below. Which line contains the unauthorized dot?
const panel = document.querySelector("[data-gidza-panel]");
panel.classList.add(".is-open");
panel.classList.remove("is-locked");
panel.classList.toggle("has-warning");
Correction:
panel.classList.add("is-open");
“A selector may begin with a dot. A class name in classList should not.” — De la Vega selector note