SUBMIT HOMEWORK

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.

  • true The panel is hidden. Gidza remains in the drawer.
  • false The panel is visible. Gidza has been summoned against policy.
  • 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”.

  • panel.hidden Current value. What the panel is doing now.
  • !panel.hidden Opposite value. If hidden, show. If visible, hide.
  • “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.

  • add Put a class on the element. The stamp is applied.
  • remove Take a class off the element. The stamp is removed from official view.
  • toggle Add it if missing, remove it if present. Administrative indecision automated.
  • 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.

  • .is-open CSS selector. Use when CSS is looking for the class.
  • "is-open" JavaScript class name. Use when classList is adding or toggling the class.
  • “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