What you'll be able to do

By the end of this page you should be able to grab an element from the page, change its text, toggle a CSS class, and place your <script> so the HTML exists before your code runs.

Previous post: Set and Map basics — this closes Phase 6. We now work in the browser with the live page.

Who this is for

  • People who wrote console-only JS and want the page to react
  • Beginners who got null from document.querySelector and did not know why
  • Anyone who put <script> in <head> and wondered why the button was “missing”

You can skip this if you already select nodes and update textContent / classList confidently. Come back when script order breaks your first DOM demo.

The DOM in one sentence

The DOM is the browser’s live tree of everything on the page — each tag becomes a node you can reach from JavaScript via document.

Scenario A — change a greeting. HTML shows “Hello.” JS finds the paragraph and replaces the text.

Scenario B — highlight a row. JS adds a class; CSS already knows what .active looks like.

Select by id: getElementById

<p id="status">Waiting…</p>
<script>
  const status = document.getElementById("status");
  status.textContent = "Ready";
</script>

Scenario A — one unique element. Ids should be unique on the page.

Scenario B — script after the element. The <p> exists before the script runs. If the script were above the <p>, getElementById would return null.

querySelector: CSS-style picks

const firstButton = document.querySelector("button");
const hero = document.querySelector(".hero");
const email = document.querySelector("#email");

Scenario A — first match only. querySelector returns one node or null.

Scenario B — many items. Use querySelectorAll (returns a NodeList) — we use it more in the next post on traversal.

Change text: textContent

const title = document.querySelector("h1");
title.textContent = "New title";

Scenario A — plain text. Safe default; user-visible words only.

Scenario B — need HTML inside? innerHTML exists but treats strings as markup — easy to misuse with user input. Prefer textContent until you know why you need HTML.

Classes: classList

const box = document.querySelector(".box");
box.classList.add("open");
box.classList.remove("hidden");
box.classList.toggle("active");

Scenario A — CSS does the look. JS toggles class names; styles live in CSS.

Scenario B — avoid box.className = "a b c" when you only want to add one class. classList keeps the rest.

Script before HTML: the classic null

<script>
  const btn = document.querySelector("#go"); // null if #go is below
</script>
<button id="go">Go</button>

Fix A — move <script> to the end of <body>.

Fix B — wait for DOM ready (later post #48). For now, end-of-body scripts are the honest beginner habit.

A tiny practice file

Save as dom-select.html.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>DOM select</title>
    <style>
      .highlight { background: #ffe082; }
    </style>
  </head>
  <body>
    <h1 id="title">Hello</h1>
    <button id="rename">Rename</button>
    <button id="toggle">Toggle highlight</button>
    <script>
      const title = document.getElementById("title");
      document.getElementById("rename").addEventListener("click", function () {
        title.textContent = "Hello from JS";
      });
      document.getElementById("toggle").addEventListener("click", function () {
        title.classList.toggle("highlight");
      });
    </script>
  </body>
</html>

Mistakes I see a lot

1. Script in <head> before elements exist.

2. Typo in selector → null → crash on .textContent. Log the node once.

3. Using getElementById("#id") — id form has no** #.

4. Replacing entire className and wiping unrelated classes.

5. innerHTML with user strings — XSS risk; use textContent first.

6. Expecting querySelectorAll to be an array. It is array-like; spread or Array.from when you need array methods.

What to try before the next post

  1. Change an h1 with textContent.
  2. Toggle a class that CSS styles.
  3. Break script order on purpose; fix by moving the script.
  4. Build dom-select.html.

Next in this series: DOM traversal — parent, children, and siblings without brittle selectors only.

Try this next outside the series

Browser JavaScript stops feeling isolated once you connect it to forms and component-oriented UI work.