JavaScript becomes powerful in the browser because it can interact with web pages through the DOM and access browser features through Browser APIs.
With JavaScript, we can:
This module covers:
DOM stands for:
Document Object Model
When the browser loads an HTML document, it reads the HTML and creates a tree-like representation of the page.
That representation is called the DOM.
Example HTML:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<h1>Hello</h1>
<p>Welcome</p>
</body>
</html>
The browser represents it approximately like this:
Document
│
└── html
│
├── head
│ │
│ └── title
│
└── body
│
├── h1
│
└── p
JavaScript can access this structure through:
document
For example:
console.log(document);
The document object represents the current webpage.
HTML creates the initial structure of a webpage.
JavaScript uses the DOM to make that page interactive.
HTML
↓
Browser
↓
DOM
↓
JavaScript
↓
Interactive Webpage
Using the DOM, JavaScript can:
Read Elements
↓
Modify Elements
↓
Create Elements
↓
Delete Elements
↓
Handle Events
Before JavaScript can modify an HTML element, it usually needs to select that element.
Suppose we have:
<h1 id="title">
Hello World
</h1>
JavaScript can find this element using different DOM selection methods.
getElementById()getElementById() selects an element using its id.
HTML:
<h1 id="title">
Hello World
</h1>
JavaScript:
const title =
document.getElementById(
"title"
);
console.log(title);
The variable title now contains the <h1> element.
Conceptually:
document
↓
Find ID "title"
↓
<h1 id="title">
Notice that we write:
"title"
not:
"#title"
with getElementById().
querySelector()querySelector() selects the first element matching a CSS selector.
HTML:
<h1 class="title">
Hello
</h1>
JavaScript:
const title =
document.querySelector(
".title"
);
Because querySelector() uses CSS selector syntax, we can select elements in many ways.
document.querySelector(
".card"
);
CSS equivalent:
.card
document.querySelector(
"#title"
);
CSS equivalent:
#title
document.querySelector(
"button"
);
This selects the first <button>.
querySelector() ExamplesHTML:
<div class="card">
<h2>Product</h2>
<button class="buy">
Buy
</button>
</div>
JavaScript:
const card =
document.querySelector(
".card"
);
const heading =
document.querySelector(
".card h2"
);
const button =
document.querySelector(
".buy"
);
querySelectorAll()querySelectorAll() selects all elements matching a CSS selector.
HTML:
<ul>
<li>Apple</li>
<li>Mango</li>
<li>Banana</li>
</ul>
JavaScript:
const items =
document.querySelectorAll(
"li"
);
The result is a:
NodeList
Example:
NodeList(3)
We can loop through it:
items.forEach(item => {
console.log(
item.textContent
);
});
Output:
Apple
Mango
Banana
querySelector() vs querySelectorAll()document.querySelector(
".card"
);
Returns:
First Matching Element
While:
document.querySelectorAll(
".card"
);
returns:
All Matching Elements
JavaScript also provides older selection methods.
getElementsByClassName()const cards =
document.getElementsByClassName(
"card"
);
Selects elements with the given class.
getElementsByTagName()const divs =
document.getElementsByTagName(
"div"
);
Selects elements by their HTML tag.
| Method | Purpose |
|---|---|
getElementById() |
Select element by ID |
querySelector() |
Select first matching CSS selector |
querySelectorAll() |
Select all matching CSS selectors |
getElementsByClassName() |
Select by class |
getElementsByTagName() |
Select by HTML tag |
In modern JavaScript, you will commonly see:
document.querySelector()
and:
document.querySelectorAll()
because they support standard CSS selectors.
After selecting an element, JavaScript can modify it.
DOM manipulation includes:
Changing Text
Changing HTML
Changing Styles
Changing Attributes
Changing Classes
Creating Elements
Removing Elements
textContentHTML:
<h1 id="title">
Hello
</h1>
JavaScript:
const title =
document.getElementById(
"title"
);
title.textContent =
"Welcome";
Result:
<h1 id="title">
Welcome
</h1>
The page changes without reloading.
textContent can also read text.
const title =
document.querySelector(
"h1"
);
console.log(
title.textContent
);
If the HTML is:
<h1>Hello World</h1>
Output:
Hello World
innerHTMLinnerHTML allows us to read or replace the HTML inside an element.
Example:
const title =
document.querySelector(
"#title"
);
title.innerHTML =
"<span>Welcome</span>";
Result:
<h1 id="title">
<span>Welcome</span>
</h1>
Unlike textContent, HTML tags inside innerHTML are interpreted by the browser.
textContent vs innerHTMLtextContent |
innerHTML |
|---|---|
| Handles text | Handles HTML |
| HTML is treated as text | HTML is parsed |
| Safer for plain text | Can introduce security risks |
| Good for user-facing text | Useful when HTML insertion is actually required |
For plain text, prefer:
element.textContent =
"Hello";
Be careful with:
element.innerHTML =
userInput;
because untrusted HTML can create Cross-Site Scripting (XSS) vulnerabilities.
JavaScript can modify inline CSS through the style property.
Example:
const title =
document.querySelector(
"h1"
);
title.style.color =
"blue";
Another example:
title.style.fontSize =
"40px";
title.style.backgroundColor =
"black";
Notice:
CSS:
background-color
JavaScript:
backgroundColor
JavaScript style properties generally use camelCase.
Although this works:
title.style.color =
"blue";
for larger applications it is usually better to define styles in CSS.
CSS:
.active {
color: blue;
font-weight: bold;
}
JavaScript:
title.classList.add(
"active"
);
This keeps:
HTML
↓
Structure
CSS
↓
Styling
JavaScript
↓
Behavior
separated.
HTML elements contain attributes such as:
<img
id="logo"
src="old.png"
alt="Logo"
>
JavaScript can modify them.
const logo =
document.getElementById(
"logo"
);
logo.setAttribute(
"src",
"logo.png"
);
Result:
<img
id="logo"
src="logo.png"
alt="Logo"
>
Use:
getAttribute()
Example:
const source =
logo.getAttribute(
"src"
);
console.log(source);
Output:
logo.png
Attributes can also be removed.
logo.removeAttribute(
"title"
);
One of the most common DOM operations is adding and removing CSS classes.
JavaScript provides:
classList
element.classList.add(
"active"
);
Example:
const menu =
document.querySelector(
".menu"
);
menu.classList.add(
"open"
);
element.classList.remove(
"active"
);
element.classList.toggle(
"active"
);
If the class exists:
Remove It
If the class does not exist:
Add It
This is extremely useful for:
Use:
classList.contains()
Example:
if (
menu.classList.contains(
"open"
)
) {
console.log(
"Menu is open"
);
}
JavaScript can create new HTML elements.
Use:
document.createElement()
Example:
const paragraph =
document.createElement(
"p"
);
Now we have created:
<p></p>
but it has not yet been added to the page.
paragraph.textContent =
"Hello World";
Now the element represents:
<p>Hello World</p>
Use:
appendChild()
Example:
document.body.appendChild(
paragraph
);
Now the paragraph appears on the webpage.
Complete example:
const paragraph =
document.createElement(
"p"
);
paragraph.textContent =
"Hello World";
document.body.appendChild(
paragraph
);
append()Modern JavaScript also provides:
append()
Example:
document.body.append(
paragraph
);
append() can also append multiple nodes or strings.
HTML:
<ul id="fruits"></ul>
JavaScript:
const fruits = [
"Apple",
"Mango",
"Banana"
];
const list =
document.querySelector(
"#fruits"
);
for (const fruit of fruits) {
const item =
document.createElement(
"li"
);
item.textContent =
fruit;
list.append(
item
);
}
Result:
<ul id="fruits">
<li>Apple</li>
<li>Mango</li>
<li>Banana</li>
</ul>
This is a basic example of dynamic UI rendering.
Use:
element.remove();
Example:
const card =
document.querySelector(
".card"
);
card.remove();
The element is removed from the DOM.
| Method / Property | Purpose |
|---|---|
textContent |
Read or change text |
innerHTML |
Read or change HTML |
style |
Modify inline CSS |
setAttribute() |
Set attribute |
getAttribute() |
Read attribute |
removeAttribute() |
Remove attribute |
classList.add() |
Add class |
classList.remove() |
Remove class |
classList.toggle() |
Toggle class |
classList.contains() |
Check class |
createElement() |
Create element |
appendChild() |
Add child element |
append() |
Append nodes or text |
remove() |
Remove element |
Websites need to respond to user actions.
Examples include:
User Clicks Button
User Types
User Submits Form
User Presses Key
User Moves Mouse
User Scrolls
These actions are called events.
| Event | Trigger |
|---|---|
click |
Element clicked |
dblclick |
Double click |
input |
Input value changes while typing |
change |
Value is committed/changed |
submit |
Form submitted |
keydown |
Key pressed |
keyup |
Key released |
mouseover |
Pointer enters element or descendant |
mouseout |
Pointer leaves element or descendant |
focus |
Element receives focus |
blur |
Element loses focus |
scroll |
Page or element scrolls |
addEventListener()The standard way to listen for events is:
addEventListener()
Syntax:
element.addEventListener(
"event",
callback
);
Conceptually:
Element
↓
Wait for Event
↓
Event Happens
↓
Run Callback
HTML:
<button id="btn">
Click Me
</button>
JavaScript:
const btn =
document.getElementById(
"btn"
);
btn.addEventListener(
"click",
() => {
console.log(
"Clicked"
);
}
);
When the button is clicked:
Clicked
btn.addEventListener(
"click",
() => {
btn.textContent =
"Clicked!";
}
);
Before:
Click Me
After clicking:
Clicked!
HTML:
<input
id="name"
type="text"
>
JavaScript:
const input =
document.getElementById(
"name"
);
input.addEventListener(
"input",
event => {
console.log(
event.target.value
);
}
);
If the user types:
Samir
JavaScript can access the current input value.
When an event happens, JavaScript provides information about that event through an event object.
Example:
button.addEventListener(
"click",
event => {
console.log(event);
}
);
The event object contains useful information.
Common properties and methods:
event.target
event.currentTarget
event.type
event.preventDefault()
event.stopPropagation()
event.targetevent.target refers to the element where the event originated.
Example:
button.addEventListener(
"click",
event => {
console.log(
event.target
);
}
);
event.currentTargetevent.currentTarget refers to the element whose event listener is currently running.
Example:
button.addEventListener(
"click",
event => {
console.log(
event.currentTarget
);
}
);
For simple button events, target and currentTarget may be the same.
They become especially important when working with event bubbling and event delegation.
HTML:
<form id="form">
<input
type="text"
id="username"
>
<button type="submit">
Submit
</button>
</form>
JavaScript:
const form =
document.getElementById(
"form"
);
form.addEventListener(
"submit",
event => {
event.preventDefault();
console.log(
"Form submitted"
);
}
);
preventDefault()Browsers have default behaviors.
For example, submitting a form normally causes navigation or a page reload.
We can prevent that using:
event.preventDefault();
Example:
form.addEventListener(
"submit",
event => {
event.preventDefault();
}
);
Now JavaScript can control what happens after submission.
This is common in modern web applications.
HTML:
<input id="search">
JavaScript:
const search =
document.querySelector(
"#search"
);
search.addEventListener(
"keydown",
event => {
console.log(
event.key
);
}
);
If the user presses Enter:
Enter
Example:
search.addEventListener(
"keydown",
event => {
if (
event.key === "Enter"
) {
console.log(
"Searching..."
);
}
}
);
Events can travel through the DOM.
Consider:
<div id="parent">
<button id="child">
Click
</button>
</div>
JavaScript:
const parent =
document.getElementById(
"parent"
);
const child =
document.getElementById(
"child"
);
parent.addEventListener(
"click",
() => {
console.log(
"Parent"
);
}
);
child.addEventListener(
"click",
() => {
console.log(
"Child"
);
}
);
Click the button.
Output:
Child
Parent
Why?
Because the event starts at the clicked element and then bubbles upward.
Button
↓
Child Handler
↓
Parent
↓
Parent Handler
↓
Higher Ancestors
This behavior is called:
Event Bubbling
Sometimes we do not want the event to continue upward.
Use:
event.stopPropagation();
Example:
child.addEventListener(
"click",
event => {
event.stopPropagation();
console.log(
"Child"
);
}
);
Now clicking the button outputs:
Child
The parent's click handler will not receive that event.
Use stopPropagation() only when the behavior is actually needed.
Event bubbling can be useful.
Instead of adding an event listener to every child element, we can add one listener to the parent.
HTML:
<ul id="list">
<li>Apple</li>
<li>Mango</li>
<li>Banana</li>
</ul>
JavaScript:
const list =
document.querySelector(
"#list"
);
list.addEventListener(
"click",
event => {
if (
event.target.matches(
"li"
)
) {
console.log(
event.target.textContent
);
}
}
);
Click:
Mango
Output:
Mango
This technique is called:
Event Delegation
It is especially useful for dynamically created elements.
The browser provides many built-in features that JavaScript can access.
These are called Browser APIs or Web APIs.
Examples:
DOM API
Storage API
Fetch API
Geolocation API
History API
Navigator API
Timers
Clipboard API
API stands for:
Application Programming Interface
An API provides a defined way for one piece of software to interact with another.
Browser APIs allow JavaScript to communicate with browser features.
JavaScript
↓
Browser API
↓
Browser Feature
For example:
JavaScript
↓
Geolocation API
↓
Device Location
In browsers, window represents the browser window and provides access to many global browser features.
Example:
console.log(window);
Many browser globals can also be accessed without writing window..
For example:
window.alert("Hello");
and:
alert("Hello");
refer to the same browser function.
alert(
"Hello"
);
Displays a browser dialog.
const result =
confirm(
"Are you sure?"
);
Returns:
true
if the user confirms, otherwise:
false
Example:
if (
confirm("Delete item?")
) {
console.log(
"Deleted"
);
}
const name =
prompt(
"Enter your name"
);
console.log(name);
prompt() allows simple text input through a browser dialog.
These dialog APIs are useful for learning and simple demos, but custom HTML dialogs are usually preferred in production interfaces.
Browsers provide timer functions for delayed and repeated execution.
The main ones are:
setTimeout()
setInterval()
clearTimeout()
clearInterval()
setTimeout()Runs a function once after a delay.
setTimeout(
() => {
console.log(
"Hello"
);
},
2000
);
After approximately:
2 Seconds
Output:
Hello
The delay is specified in milliseconds:
1000 ms = 1 second
2000 ms = 2 seconds
5000 ms = 5 seconds
setTimeout()const timer =
setTimeout(
() => {
console.log(
"Hello"
);
},
3000
);
clearTimeout(timer);
The callback is cancelled before it runs.
setInterval()Runs a function repeatedly.
const interval =
setInterval(
() => {
console.log(
"Running"
);
},
1000
);
Output:
Running
Running
Running
...
approximately every second.
clearInterval(
interval
);
localStorage allows websites to store key-value data in the browser.
Example:
localStorage.setItem(
"name",
"Samir"
);
This stores:
name → Samir
const name =
localStorage.getItem(
"name"
);
console.log(name);
Output:
Samir
localStorage.removeItem(
"name"
);
localStorage.clear();
This removes all localStorage entries for the current origin.
Suppose we have:
const user = {
name: "Samir",
age: 21
};
This is an object.
To store it:
localStorage.setItem(
"user",
JSON.stringify(user)
);
Read it:
const storedUser =
localStorage.getItem(
"user"
);
Convert it back to an object:
const userData =
JSON.parse(
storedUser
);
Now:
console.log(
userData.name
);
Output:
Samir
Common pattern:
Object
↓
JSON.stringify()
↓
String
↓
localStorage
When reading:
localStorage
↓
String
↓
JSON.parse()
↓
Object
Do not store sensitive secrets such as passwords or private authentication credentials in localStorage.
sessionStorage works similarly to localStorage.
Example:
sessionStorage.setItem(
"theme",
"dark"
);
Read:
sessionStorage.getItem(
"theme"
);
Remove:
sessionStorage.removeItem(
"theme"
);
The main difference is lifetime.
localStorage |
sessionStorage |
|---|---|
| Persists across browser sessions | Exists for the page's tab/session |
| Remains until removed | Cleared when that tab/session ends |
| Useful for persistent preferences | Useful for temporary session data |
The navigator object provides information and capabilities related to the browser and device.
Example:
console.log(
navigator.userAgent
);
Another useful property:
navigator.onLine
Returns:
true
or:
false
Example:
if (navigator.onLine) {
console.log(
"Online"
);
} else {
console.log(
"Offline"
);
}
The location object provides information about the current page URL.
Get current URL:
console.log(
location.href
);
location.href =
"https://example.com";
The browser navigates to the new URL.
location.reload();
Reloads the current page.
location.hostname
Returns the hostname.
location.pathname
Returns the current path.
location.protocol
Returns something such as:
https:
The Fetch API is used to make network requests.
For example, JavaScript can request data from a server:
fetch(
"https://api.example.com/users"
)
.then(response => {
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
Flow:
JavaScript
↓
fetch()
↓
Server
↓
Response
↓
JSON
↓
JavaScript Data
A common modern pattern is:
async function getUsers() {
try {
const response =
await fetch(
"/api/users"
);
if (!response.ok) {
throw new Error(
"Request failed"
);
}
const users =
await response.json();
console.log(users);
} catch (error) {
console.error(error);
}
}
The Fetch API is covered in more detail in the APIs section.
The Geolocation API can request the user's location.
Example:
navigator.geolocation
.getCurrentPosition(
position => {
console.log(
position.coords.latitude
);
console.log(
position.coords.longitude
);
}
);
Conceptually:
Website
↓
Request Location
↓
User Permission
↓
Browser
↓
Location Data
Location access generally requires user permission and a secure context such as HTTPS.
| API | Purpose |
|---|---|
| DOM | Interact with webpage |
| Window | Browser window/global features |
| Timers | Delayed/repeated execution |
| Local Storage | Persistent key-value storage |
| Session Storage | Session-based storage |
| Navigator | Browser/device capabilities |
| Location | Current URL and navigation |
| Fetch | Network requests |
| Geolocation | Location access |
HTML:
<button id="themeButton">
Toggle Theme
</button>
CSS:
.dark {
background: #111;
color: white;
}
JavaScript:
const button =
document.querySelector(
"#themeButton"
);
button.addEventListener(
"click",
() => {
document.body
.classList
.toggle(
"dark"
);
const isDark =
document.body
.classList
.contains(
"dark"
);
localStorage.setItem(
"theme",
isDark
? "dark"
: "light"
);
}
);
Concepts used:
DOM Selection
↓
querySelector()
Event Handling
↓
addEventListener()
DOM Manipulation
↓
classList.toggle()
Browser API
↓
localStorage
We can read the stored value when the page loads.
const theme =
localStorage.getItem(
"theme"
);
if (theme === "dark") {
document.body
.classList
.add(
"dark"
);
}
Now the user's preference can persist across visits.
HTML:
<input
id="itemInput"
type="text"
placeholder="Enter item"
>
<button id="addButton">
Add
</button>
<ul id="list"></ul>
JavaScript:
const input =
document.querySelector(
"#itemInput"
);
const button =
document.querySelector(
"#addButton"
);
const list =
document.querySelector(
"#list"
);
button.addEventListener(
"click",
() => {
const value =
input.value.trim();
if (!value) {
return;
}
const item =
document.createElement(
"li"
);
item.textContent =
value;
list.append(item);
input.value = "";
}
);
This simple example demonstrates the basic pattern behind interactive web applications:
Select Elements
↓
Listen for User Action
↓
Read Data
↓
Process Data
↓
Update DOM
The DOM is itself a Web API, but it is useful to distinguish page manipulation from other browser capabilities.
DOM
↓
Webpage Structure
↓
HTML Elements
Examples:
document.querySelector()
document.createElement()
element.remove()
Other Browser APIs provide capabilities beyond manipulating HTML.
Browser APIs
↓
Storage
Network
Location
Navigation
Timers
Device Features
Examples:
localStorage
fetch()
navigator.geolocation
setTimeout()
| Topic | Purpose |
|---|---|
| DOM | Represents the webpage |
document |
Entry point to the page DOM |
| DOM Selection | Find elements |
| DOM Manipulation | Modify elements |
querySelector() |
Find first matching element |
querySelectorAll() |
Find all matching elements |
textContent |
Read/change text |
classList |
Manage CSS classes |
createElement() |
Create elements |
| Events | Respond to actions |
| Event Object | Information about an event |
| Event Bubbling | Event travels through ancestors |
| Event Delegation | Handle child events through parent |
| Browser APIs | Access browser capabilities |
| Local Storage | Persistent browser storage |
| Session Storage | Temporary session storage |
| Fetch API | Network requests |
| Geolocation | Location access |
| Timers | Delayed/repeated execution |
JavaScript interacts with HTML through the DOM.
HTML
↓
Browser Parses HTML
↓
DOM
↓
JavaScript
↓
Select Elements
↓
Manipulate Elements
↓
Interactive UI
User interactions are handled through events:
User Action
↓
Event
↓
Event Listener
↓
JavaScript Function
↓
Update UI
JavaScript can also communicate with browser features through Browser APIs:
JavaScript
↓
Browser APIs
├── Storage
├── Network
├── Location
├── Navigation
├── Timers
└── Device Features
A common frontend workflow looks like:
const button =
document.querySelector(
"#button"
);
button.addEventListener(
"click",
() => {
document.body
.classList
.toggle(
"active"
);
}
);
The core pattern is:
Select
↓
Listen
↓
Process
↓
Update
Understanding the DOM, events, and Browser APIs is essential because they are the foundation of browser-based JavaScript.
Libraries and frameworks such as React and Next.js provide higher-level ways to build interfaces, but underneath them the browser still works with:
DOM
+
Events
+
Browser APIs