MarzleyTech Learn

Home / Learn / JavaScript / The DOM and events: changing the page and responding to clicks, typing and more

The DOM and events: changing the page and responding to clicks, typing and more

This is where JavaScript and web pages meet. The DOM (Document Object Model) is the browser's live version of your HTML that JavaScript can read and change: update text, add items to a list, show an error, switch to dark mode. Events are things that happen (a click, typing, submitting a form, scrolling) that JavaScript can respond to. Master these and you can build interactive features for any website.

What is the DOM?

When the browser loads HTML, it builds a tree of objects in memory, one object per element, text and attribute. That tree is the DOM.

document
└── html
    ├── head
    │   └── title
    └── body
        ├── h1  "Juma's Shop"
        └── ul#cart
            ├── li  "Unga"
            └── li  "Sugar"

Important: the DOM isn't your HTML file. JavaScript changes the DOM in memory; your file on the server stays the same (refresh and changes disappear unless saved somewhere).

The DOM is a browser feature, so DOM examples here run as HTML pages with a <script>.

Selecting elements

HTML · runs live in the interactive lesson
<h1 id="title">Juma's Shop</h1>
<p class="note">Open daily 8am–8pm</p>
<ul id="cart"><li>Unga</li><li>Sugar</li><li>Milk</li></ul>
<script>
  const title = document.querySelector("#title");        // first match (CSS selector)
  const note = document.querySelector(".note");
  const items = document.querySelectorAll("#cart li");    // all matches (a NodeList)
  const sameTitle = document.getElementById("title");     // by id (no #)

  console.log(title.textContent);
  console.log(note.textContent);
  console.log(items.length, "items in the cart");
  items.forEach((li) => console.log("-", li.textContent));
</script>
MethodReturns
document.querySelector(css)The first matching element, or null
document.querySelectorAll(css)All matches (NodeList; use forEach or for...of)
document.getElementById(id)Element with that id, or null
element.querySelector(css)Search inside an element

If a selector finds nothing, you get null, and using it (null.textContent) throws an error. Check spelling and make sure the script runs after the HTML exists (script at the end of <body> or defer).

Changing content

HTML · runs live in the interactive lesson
<h2 id="msg">Loading…</h2>
<p id="price"></p>
<div id="box"></div>
<script>
  document.querySelector("#msg").textContent = "Welcome back, Wanjiku!";
  document.querySelector("#price").textContent = "Total: KSh " + (180 * 3).toLocaleString();

  // innerHTML parses HTML: only use with trusted content
  document.querySelector("#box").innerHTML = "<strong>Free delivery</strong> on orders over KSh 2,000";
</script>

textContent vs innerHTML

textContentinnerHTML
Treats value asPlain textHTML code
Safe with user inputYesNo
Use forNames, messages, numbersYour own trusted HTML templates

Attributes, classes and styles

HTML · runs live in the interactive lesson
<style>
  .highlight { background: #fef3c7; border-left: 4px solid #f59e0b; padding: 8px; }
  .hidden { display: none; }
</style>
<p id="offer">Weekend offer: 10% off</p>
<a id="link" href="#">Our shop</a>
<img id="pic" src="https://picsum.photos/120/80" alt="Shop">
<p id="secret" class="hidden">Secret discount code: KARIBU10</p>
<script>
  const offer = document.querySelector("#offer");
  offer.classList.add("highlight");          // add a class
  offer.classList.toggle("bold");            // add if missing, remove if present
  console.log(offer.classList.contains("highlight"));   // true

  const link = document.querySelector("#link");
  link.setAttribute("href", "https://marzleytechsolutions.co.ke");
  link.textContent = "Visit Marzley Tech";

  document.querySelector("#pic").alt = "Inside our Kisumu shop";

  document.querySelector("#secret").classList.remove("hidden");   // show it

  offer.style.fontSize = "20px";             // inline style (camelCase property)
</script>

Prefer classes over inline styles: keep design in CSS, and use JavaScript to add or remove classes (is-open, is-active, has-error). It's cleaner and easier to maintain.

Creating and removing elements

HTML · runs live in the interactive lesson
<ul id="list"></ul>
<script>
  const list = document.querySelector("#list");
  const products = ["Unga 2kg", "Sugar 1kg", "Milk 500ml"];

  for (const name of products) {
    const li = document.createElement("li");   // create
    li.textContent = name;                     // safe text
    list.append(li);                           // insert at the end
  }

  const first = document.createElement("li");
  first.textContent = "Bread (new!)";
  list.prepend(first);                         // insert at the start

  list.lastElementChild.remove();              // remove the last item
</script>

Other insert methods: before(), after(), insertAdjacentHTML() (trusted HTML only), replaceWith().

Events

An event is a signal that something happened. You attach a listener: a function that runs when the event occurs.

HTML · runs live in the interactive lesson
<button id="btn">Add to cart</button>
<p id="count">Items in cart: 0</p>
<script>
  let count = 0;
  const btn = document.querySelector("#btn");
  const out = document.querySelector("#count");

  btn.addEventListener("click", () => {
    count++;
    out.textContent = "Items in cart: " + count;
  });
</script>

element.addEventListener("eventName", function). Avoid old inline onclick="..." attributes in HTML: they mix code into markup and are blocked by strict security policies (CSP).

Common events

EventFires when
clickElement is clicked/tapped (also Enter/Space on buttons)
inputValue of an input changes (every keystroke)
changeValue committed (select changed, checkbox toggled, input left)
submitForm is submitted
keydown / keyupKey pressed / released
focus / blurElement gains / loses focus
mouseenter / mouseleaveMouse enters / leaves (no equivalent on touch screens)
scrollPage or element scrolls
DOMContentLoadedHTML is fully parsed
loadPage and all images/resources loaded

The event object

The listener receives an event object with details:

HTML · runs live in the interactive lesson
<input id="search" placeholder="Search products">
<p id="info"></p>
<script>
  const search = document.querySelector("#search");
  const info = document.querySelector("#info");

  search.addEventListener("input", (event) => {
    info.textContent = `You typed: "${event.target.value}" (${event.target.value.length} characters)`;
  });

  search.addEventListener("keydown", (event) => {
    if (event.key === "Escape") { search.value = ""; info.textContent = "Cleared"; }
  });
</script>
  • event.target: the element that triggered the event.
  • event.key: which key was pressed.
  • event.preventDefault(): stop the browser's default action (e.g. form reload, link navigation).

Forms with JavaScript

HTML · runs live in the interactive lesson
<form id="order">
  <label for="phone">M-Pesa number</label>
  <input id="phone" name="phone" type="tel" placeholder="0712 345 678">
  <label for="qty">Quantity</label>
  <input id="qty" name="qty" type="number" value="1" min="1">
  <button type="submit">Order</button>
  <p id="feedback" role="status"></p>
</form>
<script>
  const form = document.querySelector("#order");
  const feedback = document.querySelector("#feedback");

  form.addEventListener("submit", (e) => {
    e.preventDefault();                          // stop the page reloading
    const phone = form.phone.value.replace(/\D/g, "");
    const qty = Number(form.qty.value);

    if (!/^(0|254)[17]\d{8}$/.test(phone)) {
      feedback.textContent = "Enter a valid Safaricom or Airtel number.";
      form.phone.focus();
      return;
    }
    feedback.textContent = `Order received: ${qty} item(s). We'll send an M-Pesa prompt to ${phone}.`;
  });
</script>

Remember: browser-side validation is for convenience; the server must validate again (anyone can bypass JavaScript).

Event delegation

Adding a listener to every item in a long or changing list is wasteful, and new items wouldn't have listeners. Instead, listen on the parent and check what was clicked (events bubble up from the target to its ancestors):

HTML · runs live in the interactive lesson
<ul id="tasks">
  <li>Buy unga <button class="del">✕</button></li>
  <li>Pay rent <button class="del">✕</button></li>
</ul>
<button id="add">Add task</button>
<script>
  const tasks = document.querySelector("#tasks");
  tasks.addEventListener("click", (e) => {
    const btn = e.target.closest(".del");      // did the click happen on a delete button?
    if (btn) btn.closest("li").remove();
  });

  let n = 1;
  document.querySelector("#add").addEventListener("click", () => {
    const li = document.createElement("li");
    li.textContent = "New task " + n++ + " ";
    const del = document.createElement("button");
    del.className = "del";
    del.textContent = "✕";
    li.append(del);
    tasks.append(li);                            // works without adding new listeners
  });
</script>
Think about it: Why does deleting a newly added task still work, even though no listener was added to its button?Show answer

Because the listener is on the <ul>. Clicks on any button inside bubble up to the <ul>, where the code checks e.target.closest(".del"). Any present or future child button is handled by that single parent listener.

Accessibility and performance tips

  • Use real <button> elements for clickable actions (keyboard and screen reader support for free).
  • Announce dynamic messages with role="status" or aria-live="polite" (as in the form example).
  • Move focus sensibly (e.g. to the first error field, or into an opened dialog).
  • Batch DOM changes: build items then insert once (e.g. using a DocumentFragment or building an array of elements) for big lists.
  • For scroll and input events that fire very often, keep handlers light (or debounce them).

Common mistakes

MistakeFix
Script runs before the HTML exists (null errors)Script at end of <body> or defer
Wrong selector ("title" instead of "#title")Use CSS selector syntax
innerHTML with user inputtextContent / createElement
Calling the function when adding the listener: addEventListener("click", save())Pass it: addEventListener("click", save)
Forgetting preventDefault() on form submitPage reloads and data is lost
Comparing input values as numbersNumber(input.value)
div with click handler instead of buttonUse <button>

Practice tasks

  1. Build a counter with + and − buttons that never goes below 0.
  2. Make a "Show more" button that reveals hidden text by toggling a class.
  3. Build a live character counter for a 160-character SMS textarea.
  4. Create a product list from an array of objects using createElement.
  5. Build a to-do list where tasks can be added and deleted (use event delegation).

Summary

  • The DOM is the browser's live tree of the page; JavaScript reads and changes it.
  • Select with querySelector, querySelectorAll, getElementById.
  • Change content with textContent (safe) or innerHTML (trusted HTML only); change classes with classList; attributes with setAttribute or properties.
  • Create with createElement, insert with append/prepend, remove with remove().
  • Respond to events with addEventListener; use the event object (target, key, preventDefault()).
  • Handle forms with submit + preventDefault; use event delegation for dynamic lists; keep it accessible.

Check yourself

  1. What does DOM stand for? Write the first word.

    Show answer

    Document

  2. Which method selects the first element matching a CSS selector?

    Show answer

    querySelector

  3. Which property safely sets plain text in an element?

    Show answer

    textContent

  4. Which method attaches an event listener?

    Show answer

    addEventListener

  5. Which event fires on every keystroke in an input?

    Show answer

    input

  6. Which event method stops a form from reloading the page?

    Show answer

    preventDefault

  7. Which classList method adds a class if missing and removes it if present?

    Show answer

    toggle

  8. What is the attack called when user input is run as code through innerHTML? (three letters)

    Show answer

    XSS

Exercise

Using document.querySelector, change the text of the <h1> to Done and print it with console.log.

Do this exercise in the live editor

Lesson 12 of 21 in JavaScript · Printable course notes