Lesson Progress
0% Complete

JavaScript (JS) is the language that makes web pages interactive. HTML gives structure, CSS controls presentation, and JavaScript adds behaviour (for example: opening a menu, validating a form, loading content without reloading the page, and updating the page based on user actions).

This topic focuses on core JavaScript concepts and how to use them to work with the DOM (Document Object Model).


1) JavaScript in the Browser: What the DOM Is

When a browser loads an HTML page, it builds a live “tree” representation of the page called the DOM. JavaScript can:

  • Read what is on the page (text, attributes, input values)
  • Change what is on the page (update text, add/remove elements, toggle classes)
  • React to the user (clicks, typing, submitting forms, scrolling)

Think of the DOM as JavaScript’s way to access and control the HTML.


2) Variables and Data Types

Variables store values so you can reuse them and change them.

let, const, and var

  • const: use when the variable reference should not change (recommended default).
  • let: use when you need to reassign a new value.
  • var: older style; avoid in modern code unless you must support very old patterns.
const siteName = "My Portfolio";
let itemsInCart = 0;

itemsInCart = 3; // allowed because it's let
// siteName = "New Name"; // not allowed because it's const

Common data types

  • String: "Hello"
  • Number: 42
  • Boolean: true / false
  • Null: explicitly “nothing”
  • Undefined: not assigned
  • Object: { name: "Ayesha" }
  • Array: ["Home", "About", "Contact"]
const user = { name: "Ayesha", isMember: true };
const pages = ["Home", "Services", "Contact"];

3) Operators and Basic Logic

You will often compare values and make decisions.

Comparison and equality

  • === (strict equality) compares value and type (recommended)
  • == (loose equality) converts types (avoid most of the time)
console.log(5 === "5"); // false
console.log(5 == "5");  // true (type conversion happens)

Conditionals (if, else)

const age = 17;

if (age >= 18) {
  console.log("You may proceed.");
} else {
  console.log("You must be 18 or older.");
}

Logical operators

  • && (and)
  • || (or)
  • ! (not)
const isLoggedIn = true;
const isAdmin = false;

if (isLoggedIn && isAdmin) {
  console.log("Show admin dashboard");
}

4) Functions: Reusable Behaviour

Functions group steps into reusable blocks.

Function declaration

function greet(name) {
  return `Hello, ${name}`;
}

console.log(greet("Sibusiso"));

Arrow functions (common in modern JS)

const add = (a, b) => a + b;
console.log(add(2, 3));

Why functions matter in DOM work

You will frequently write functions to:

  • validate inputs
  • update the UI
  • handle events (click, submit, input)

5) Selecting Elements in the DOM

To interact with the page, you first select elements.

Common selectors

  • document.querySelector() returns the first match
  • document.querySelectorAll() returns all matches (a NodeList)
const heading = document.querySelector("h1");
const navLinks = document.querySelectorAll(".nav a");
const emailInput = document.querySelector("#email");

Tip: Use IDs for unique elements (#email) and classes for groups (.nav a).


6) Reading and Changing Content

Once you have an element, you can read or update it.

Text updates

  • textContent sets/gets text only
  • innerHTML sets/gets HTML (use carefully)
const message = document.querySelector("#message");

message.textContent = "Saved successfully.";

Use innerHTML only when you control the content (to avoid security issues like XSS):

const list = document.querySelector("#items");
list.innerHTML = "<li>Milk</li><li>Bread</li>";

Attributes

const logo = document.querySelector("img");

logo.setAttribute("alt", "Company logo");
console.log(logo.getAttribute("src"));

7) Changing Styles with Classes (Preferred)

Avoid setting inline styles directly where possible. Prefer toggling classes so CSS remains responsible for design.

const banner = document.querySelector(".banner");

banner.classList.add("banner--success");
banner.classList.remove("banner--error");
banner.classList.toggle("is-hidden");

In CSS you might have:

.is-hidden { display: none; }

This keeps your code clean and easier to maintain.


8) Events: Reacting to User Actions

An event is something that happens in the browser: a click, key press, form submit, input change, etc.

You attach an event listener to an element:

const button = document.querySelector("#saveBtn");

button.addEventListener("click", () => {
  console.log("Button clicked");
});

Common events you will use often

  • click (buttons, links, cards)
  • submit (forms)
  • input (live typing in a field)
  • change (select menus, checkbox changes)
  • keydown (keyboard interaction)

9) Example: Toggle a Mobile Menu

This is a common real-world pattern: clicking a hamburger button opens/closes navigation.

HTML

<button id="menuBtn" aria-expanded="false" aria-controls="mainNav">
  Menu
</button>

<nav id="mainNav" class="nav is-hidden">
  <a href="#home">Home</a>
  <a href="#about">About</a>
  <a href="#contact">Contact</a>
</nav>

CSS

.is-hidden { display: none; }

JavaScript

const menuBtn = document.querySelector("#menuBtn");
const mainNav = document.querySelector("#mainNav");

menuBtn.addEventListener("click", () => {
  const isHidden = mainNav.classList.toggle("is-hidden");
  menuBtn.setAttribute("aria-expanded", String(!isHidden));
});

Accessibility note (WCAG-friendly):

  • aria-expanded communicates state to screen readers.
  • Using a real <button> ensures keyboard support by default.

10) Example: Form Validation (Client-Side)

Client-side validation improves user experience, but it does not replace server-side validation.

HTML

<form id="signupForm" novalidate>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" />

  <p id="emailError" class="error is-hidden">Please enter a valid email address.</p>

  <button type="submit">Sign up</button>
</form>

JavaScript

const form = document.querySelector("#signupForm");
const email = document.querySelector("#email");
const emailError = document.querySelector("#emailError");

function isValidEmail(value) {
  // Simple pattern; real-world apps may use more robust checks.
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}

form.addEventListener("submit", (event) => {
  const emailValue = email.value.trim();

  if (!isValidEmail(emailValue)) {
    event.preventDefault(); // stop form submission
    emailError.classList.remove("is-hidden");
    email.setAttribute("aria-invalid", "true");
    email.focus();
    return;
  }

  // Valid state
  emailError.classList.add("is-hidden");
  email.removeAttribute("aria-invalid");
});

Good practice:

  • Use trim() to avoid spaces causing false “valid” inputs.
  • Give feedback near the field.
  • Move focus to the first invalid field.

11) Creating, Adding, and Removing Elements

You can build dynamic content (for example: a list of tasks, comments, products).

const list = document.querySelector("#taskList");
const addBtn = document.querySelector("#addTaskBtn");
const input = document.querySelector("#taskName");

addBtn.addEventListener("click", () => {
  const name = input.value.trim();
  if (name === "") return;

  const li = document.createElement("li");
  li.textContent = name;

  // Add a remove button inside the list item
  const removeBtn = document.createElement("button");
  removeBtn.type = "button";
  removeBtn.textContent = "Remove";

  removeBtn.addEventListener("click", () => {
    li.remove();
  });

  li.appendChild(removeBtn);
  list.appendChild(li);

  input.value = "";
  input.focus();
});

This pattern is useful for:

  • To-do lists
  • Cart items
  • Adding form sections dynamically

12) Event Bubbling and Event Delegation (Useful for Dynamic Lists)

If you add items dynamically, attaching listeners to each new item can get messy. Event delegation attaches one listener to a parent and checks what was clicked.

const list = document.querySelector("#taskList");

list.addEventListener("click", (event) => {
  if (event.target.matches("button.remove")) {
    const li = event.target.closest("li");
    li.remove();
  }
});

This works well when list items are created later.


13) Practical Tips for Clean, Reliable JavaScript

  • Put your script at the end of <body>, or use defer in the <head>:
    <script src="app.js" defer></script>
    
  • Keep behaviour in JS, styling in CSS, structure in HTML.
  • Use const by default; switch to let only when needed.
  • Use === for comparisons.
  • Prefer class toggling over inline styling.
  • Always consider keyboard and screen reader users when building interactions.

14) Mini-Checklist: What You Should Be Able to Do After This Topic

You should be able to:

  • declare variables with let and const
  • write and call functions (including arrow functions)
  • select DOM elements with querySelector / querySelectorAll
  • update text and attributes safely
  • add and remove classes to change UI state
  • handle common events (click, submit, input)
  • create and append elements dynamically
  • build simple interactive features like menus and form validation