Lesson 05

DOM & Events

Select elements, update the page, and respond to user actions.

This lesson

What you’ll learn

Progress

Track this lesson

Sign in to save this lesson to your learning dashboard.

Log in to track progress

What the DOM is

The DOM is the browser’s live object model of your HTML. JavaScript can read it, change text, update attributes, add classes, and create or remove elements.

Selecting elements

querySelector() returns the first matching element. querySelectorAll() returns a collection of matches. Data attributes such as data-menu-button make clear JavaScript hooks because they describe behaviour without tying the script to a visual class name.

Always make sure an element exists before using it if your script is shared across many pages. A guard clause such as if (!button || !menu) return; prevents a missing optional component from breaking unrelated page behaviour.

Changing state

A common professional pattern is to keep visual styling in CSS and use JavaScript to add, remove, or toggle state classes. Use the hidden property for simple show-and-hide behaviour and class changes when CSS needs to style a state such as is-open or is-selected.

Events

Events happen when users click, type, submit forms, scroll, or interact with controls. Event listeners connect those actions to functions.

Accessible interaction

Prefer native buttons for actions. When showing or hiding content, update ARIA attributes such as aria-expanded where appropriate. Keep the visible label accurate as well: if a button opens details, its label should change from “Show details” to “Hide details” when the panel opens.

Rendering user-entered content safely

When adding plain text supplied by a user, prefer textContent. It treats the value as text rather than as HTML markup. Use innerHTML only when you control and trust the markup being inserted. This distinction matters when you build comments, notes, task lists, or search results.

Example code

const button = document.querySelector("[data-menu-button]");
const menu = document.querySelector("[data-menu]");

button.addEventListener("click", () => {
  const isOpen = menu.classList.toggle("is-open");
  button.setAttribute("aria-expanded", String(isOpen));
});

Applied example: add a task safely

This example creates new elements and uses textContent so typed content is displayed as text.

const form = document.querySelector("[data-task-form]");
const input = document.querySelector("[data-task-input]");
const list = document.querySelector("[data-task-list]");

if (form && input && list) {
  form.addEventListener("submit", (event) => {
    event.preventDefault();

    const title = input.value.trim();
    if (!title) return;

    const item = document.createElement("li");
    item.textContent = title;
    list.append(item);
    form.reset();
  });
}

Guided example: how to approach this lesson

Use these steps as a practical build process. The goal is not just to read the concept, but to know exactly how to apply it in your own page.

Step 1: Mark the HTML

Add useful IDs, classes, or data attributes to the elements JavaScript needs to control.

Step 2: Select the elements

Use querySelector or querySelectorAll and check that the elements exist.

Step 3: Listen for an event

Attach an event listener for click, input, submit, or another user action.

Step 4: Update the interface

Change text, classes, attributes, or hidden states so users receive feedback.

More examples

Compare these examples carefully. The improved version shows the kind of code pattern you should aim for when building your own project.

HTML for a toggle

<button data-details-button aria-expanded="false">
  Show details
</button>

<div data-details hidden>
  <p>This extra content can be shown or hidden.</p>
</div>

The button and panel have clear hooks for JavaScript and accessible state.

JavaScript for a toggle

const button = document.querySelector("[data-details-button]");
const details = document.querySelector("[data-details]");

button.addEventListener("click", () => {
  const isHidden = details.hidden;
  details.hidden = !isHidden;
  button.setAttribute("aria-expanded", String(isHidden));
  button.textContent = isHidden ? "Hide details" : "Show details";
});

This updates both the visual state and the accessibility state.

Before moving on

Use this checklist to make sure you understand the lesson well enough to apply it without copying blindly.

  • Is the interactive element a real button?
  • Does JavaScript update visible text or state?
  • Are ARIA attributes updated when state changes?
  • Can the interaction work with a keyboard?

Common mistakes to avoid

  • Running DOM code before elements exist.
  • Using clickable divs instead of buttons.
  • Changing visual state without ARIA state.
  • Using innerHTML for untrusted content.

Practice task

Build a three-question FAQ accordion for your responsive homepage.

Required outcome

  • Use real buttons with aria-expanded and aria-controls.
  • Use hidden panels and update the expanded state whenever a panel opens or closes.
  • Change each button label so its current action remains clear.
  • Confirm every accordion control works with Tab and Enter.

Stretch goal: Close the previously open answer when a different question opens.