Lesson 12 / JavaScript

JavaScript in the DOM

Time
55 min
Type
Reading + Interactive
Level
Intermediate
Use
Core

Use JavaScript and the Document Object Model to select elements, change content, respond to events, and create dynamic interfaces.

Course Role

Core

Part of the main course path. Prioritize this before moving to optional polish or deeper references.

Teacher Notes / In-Class Use

Demo Live

  • Use the DOM lab to show select, change, listen, and respond as the core JavaScript pattern.
  • Compare textContent, classList, setAttribute, and appendChild as different kinds of DOM changes.

Try In Class

  • Have students create a button that toggles a class on one visible element.
  • Ask students to write one console.log before changing the DOM so they can confirm the event fired.

Submit Or Check

  • The interaction should still work after refresh and should not require inline onclick attributes.
  • Students should be able to point to the selected element, the event listener, and the changed class or content.

Watch For

  • Scripts running before the HTML exists because the script is loaded too early.
  • Students changing inline styles directly when toggling a class would be clearer.

Learning Goals

  • Explain the DOM as a living representation of an HTML document
  • Modify DOM element content, attributes, styles, and classes
  • Use event listeners and the event object to respond to user actions

Interactive Demo

How to use this demo.

Use the demo as a small lab. Change one thing, observe the result, then connect it back to your own project.

What To Try

  • Click each action button and watch the preview and code sample update.
  • Reset the demo, then predict what will change before pressing the next button.

What Changes

  • Text, classes, attributes, and list items update through JavaScript.
  • The code sample shows the DOM method behind each interaction.

What To Notice

  • Most interactions follow the pattern: select something, listen for an event, change something.
  • Changing classes is usually cleaner than writing many inline styles from JavaScript.

Apply It

  • Add one button to your project that toggles a class on a visible element.

Interactive Demo

DOM Interaction Lab

Use the controls to change content, classes, attributes, and elements in the preview. The code updates to show the JavaScript behind the action.

Ready

Original card title

JavaScript can select this text and update it after the page loads.

Visit LSU
  • Existing list item
const title = document.querySelector('[data-dom-title]');
title.textContent = 'Updated by JavaScript';

What to notice

  • JavaScript selects elements before it changes them.
  • classList changes styling without rewriting the HTML.
  • createElement and appendChild add new content to the page.

Try this

  • Click each action and read the generated code.
  • Reset the demo, then predict what each action will change.
  • Rebuild one action in your own script.js file.

This demo uses extra JavaScript for teaching. The code sample shows the pattern to practice. View full demo source.

What This Teaches

This lesson teaches how JavaScript interacts with the Document Object Model, or DOM.

The browser reads your HTML and creates the DOM: a structured representation of the page that JavaScript can read and update after the page loads.

You will learn a repeatable workflow: select an element, listen for an event, then change content, classes, attributes, or elements.

Core Workflow: Select, Listen, Change

Most beginner DOM interactions follow the same pattern.

  • Select an element with document.querySelector() or another selector method.
  • Listen for an event with addEventListener().
  • Change something with textContent, classList, attributes, or new elements.
const button = document.querySelector('.menu-button');

button.addEventListener('click', () => {
  document.body.classList.toggle('menu-open');
});

Adding JavaScript to Your Web Page

You can include JavaScript in your HTML document in three common ways.

For class projects, an external file loaded with defer is the preferred approach.

Inline

Inline JavaScript is written directly in an HTML attribute like onclick.

Recognize this pattern in older examples, but avoid it for class projects because it mixes behavior into markup.

<button onclick="alert('Hello!')">Click me</button>

Internal

Internal JavaScript is written inside script tags in the HTML file.

This is acceptable for quick demos, but it becomes hard to maintain as a project grows.

<head>
  <script>
    // Your JavaScript code here
  </script>
</head>

External

External JavaScript is placed in a separate file and linked with the src attribute.

Use defer so the browser downloads the script while parsing the HTML, but runs it after the HTML is ready.

defer helps prevent the common error where JavaScript tries to select an element before that element exists in the DOM.

<head>
  <script src="script.js" defer></script>
</head>

Selecting Elements

Before JavaScript can change something, it needs a reference to the element.

MethodUse For
document.querySelector()Selects the first element that matches a CSS selector.
document.querySelectorAll()Selects all matching elements as a list-like collection.
document.getElementById()Selects one element by its id.
const button = document.querySelector('.menu-button');
const cards = document.querySelectorAll('.card');
const mainNav = document.getElementById('main-nav');

When a Selector Finds Nothing

If a selector does not match anything, querySelector() returns null.

Check that the element exists before calling methods like addEventListener().

const button = document.querySelector('.menu-button');

if (button) {
  button.addEventListener('click', () => {
    document.body.classList.toggle('menu-open');
  });
}

Interactive Practice: DOM Interaction Lab

Use the DOM Interaction Lab above to change text, toggle a class, update an attribute, and add a list item.

Read the generated code after each action. Notice that every action starts by selecting an element before changing it.

Modifying Content Safely

Use textContent when inserting plain text. Use innerHTML only when the HTML is trusted and you understand the risk.

Property or MethodUse ForCaution
textContentChanging plain text.Best default for beginner projects.
innerHTMLReplacing HTML inside an element.Do not use with user-provided content.
createElement()Building structured content safely.Takes more steps but gives more control.
const message = document.querySelector('.message');

message.textContent = 'Saved successfully.';

Modifying Attributes

Attributes store extra information on HTML elements. JavaScript can read and update them.

const link = document.querySelector('.resource-link');

link.href = 'https://developer.mozilla.org/';
link.textContent = 'Read MDN';

Changing Classes Instead of Inline Styles

For most interface changes, toggle a class instead of writing many inline styles with JavaScript.

This keeps styling in CSS and behavior in JavaScript.

const card = document.querySelector('.card');

card.classList.toggle('is-highlighted');

Working with classList

The classList API is the preferred way to work with an element's classes.

  • add(className): Adds a class to the element.
  • remove(className): Removes a class from the element.
  • toggle(className): Toggles a class on or off.
  • contains(className): Checks whether the element has a specific class.
const menu = document.querySelector('.site-menu');

menu.classList.toggle('is-open');

if (menu.classList.contains('is-open')) {
  console.log('Menu is open');
}

Traversing the DOM

DOM traversal means moving between related elements after you have selected one element.

For beginners, element-based properties are usually easier than node-based properties because they skip whitespace text nodes.

PropertyMeaning
parentElementThe parent element.
childrenThe child elements.
firstElementChildThe first child element.
nextElementSiblingThe next sibling element.
previousElementSiblingThe previous sibling element.
const item = document.querySelector('.faq-item');
const parent = item.parentElement;
const nextItem = item.nextElementSibling;

Creating and Inserting Elements

JavaScript allows you to dynamically create new elements and insert them into the DOM.

const item = document.createElement('li');
item.textContent = 'New list item';

const list = document.querySelector('.task-list');
list.appendChild(item);

Event Listeners: Responding to User Actions

Event listeners run JavaScript when something happens, such as a click, form submission, or text input.

element.addEventListener('click', () => {
  // Code to execute when the element is clicked
});

Common Event Types

EventUse For
clickButtons, menu toggles, and simple interactions.
inputReacting while a user types or changes a control.
changeReacting after a form control value changes.
submitHandling a form submission.
keydownResponding to keyboard input.

Using the Event Object

When an event occurs, an event object is passed to the listener function.

The event object includes information like event.target, event.type, and methods like preventDefault().

const form = document.querySelector('.signup-form');

form.addEventListener('submit', (event) => {
  event.preventDefault();
  console.log('Handle the form with JavaScript');
});

Accessible Menu Toggle

A responsive menu toggle should use a real button, update aria-expanded, and show or hide the controlled menu.

<button class="menu-button" aria-expanded="false" aria-controls="site-menu">
  Menu
</button>

<nav id="site-menu" hidden>
  <a href="/">Home</a>
  <a href="/projects/">Projects</a>
</nav>

Accessible Menu Toggle JavaScript

const button = document.querySelector('.menu-button');
const menu = document.querySelector('#site-menu');

button.addEventListener('click', () => {
  const isOpen = button.getAttribute('aria-expanded') === 'true';

  button.setAttribute('aria-expanded', String(!isOpen));
  menu.hidden = isOpen;
});

Working with Multiple Elements

Use querySelectorAll() when the page has multiple matching elements. Then loop over the collection and attach behavior to each one.

const buttons = document.querySelectorAll('.faq-button');

buttons.forEach((button) => {
  button.addEventListener('click', () => {
    button.classList.toggle('is-open');
  });
});

Common Mistakes

MistakeWhy it happensFix
Script runs before HTML existsJavaScript executes before the element is parsed.Load external scripts with defer.
Selector returns nullThe selector does not match the HTML.Check spelling, class dots, ids, and timing.
Forgetting the dot in .classquerySelector() uses CSS selector syntax.Use .menu-button for classes and #site-menu for ids.
Using innerHTML for user inputUntrusted HTML can create security problems.Use textContent or create elements manually.
Adding one listener to many elements incorrectlyquerySelector() only returns the first match.Use querySelectorAll() and loop.
Changing many inline stylesCSS and JS become tangled.Toggle classes and keep visual styling in CSS.

Debugging Checklist

  • Open DevTools Console and read the exact error message.
  • Check whether the selected element is null.
  • Confirm the script is loaded with defer or placed after the HTML it uses.
  • Log selected elements with console.log() to verify selectors.
  • Confirm event names are lowercase, such as click and submit.
  • Check whether a class is being added in the Elements panel.
  • Prefer changing one thing at a time, then retest.

Additional Resources

MDN: Introduction to the DOM | MDN: querySelector | classList API - MDN | Events Documentation - MDN

Checkpoint

Before moving on, make sure these feel true.

  • I can select an element from the DOM.
  • I can respond to a user event with addEventListener.
  • I can change content, classes, or attributes without using inline JavaScript.

Project Connection

This lesson supports current class projects.

Practice

  • Load an external script.js file with defer.
  • Select one element with document.querySelector() and update its textContent.
  • Create a button that toggles a class with classList.toggle().
  • Build a show/hide FAQ item with a real button.
  • Build a menu toggle that updates aria-expanded.
  • Handle a simple form submit event with preventDefault().
  • Use querySelectorAll() to attach click behavior to multiple buttons.
  • Create a new list item with createElement() and add it with appendChild().
  • Use DevTools Console to debug a selector that returns null.