JavaScript Core/
Lesson

You have built a webpage with HTML and styled it with CSS. But right now it is static, nothing responds to the user. The magic happens when JavaScript starts interacting with those elements. Before you can change anything on the page, you need to grab it first.

Think of the DOMWhat is dom?The Document Object Model - the browser's live representation of your HTML page as a tree of objects that JavaScript can read and modify. like a warehouse full of boxes. You cannot rearrange the boxes until you know which ones you are looking for. Selecting elements is how you tell JavaScript: "Go find this specific box for me."

The modern way: querySelector

If you only learn one method for selecting elements, make it querySelector. It is powerful, flexible, and uses the same syntax you already know from CSS.

// Select by ID
const header = document.querySelector('#header');

// Select by class
const firstButton = document.querySelector('.button');

// Select by tag
const mainTitle = document.querySelector('h1');

// CSS combinators work too
const navLink = document.querySelector('nav a');
const activeItem = document.querySelector('.list .active');

querySelector returns null if nothing matches. This is one of the most common sources of bugs in front-end code:

const btn = document.querySelector('.submit-btn');
btn.addEventListener('click', handleClick);  // TypeError if btn is null!

// Always check first
if (btn) {
  btn.addEventListener('click', handleClick);
}
02

Selecting multiple elements

Use querySelectorAll when you need all matching elements, not just the first:

const allCards = document.querySelectorAll('.card');
const listItems = document.querySelectorAll('li');
const navLinks = document.querySelectorAll('nav a');

It returns a NodeList, a collection that looks like an array but is not one:

const buttons = document.querySelectorAll('.btn');

buttons[0];           // first button
buttons.length;       // how many
buttons.forEach(b => b.style.color = 'blue');  // forEach works

// But map, filter, find do NOT work - convert first
const arr = Array.from(buttons);
const saveButtons = arr.filter(b => b.textContent.includes('Save'));
AI pitfall, no null-checks on querySelector results: AI tools call document.querySelector() or document.getElementById() and immediately use the result without checking if it is null. If the element does not exist, because it loads later, the ID has a typo, or the page structure changed, you get a TypeError: Cannot read properties of null crash. AI also tends to use getElementById for everything, even when querySelector with a CSS selector is cleaner and more flexible. Worse, AI almost never uses querySelectorAll, it selects one element and calls it done, even when the task clearly requires selecting multiple elements (like "highlight all error messages"). Always null-check before using a selected element. Use querySelector with CSS selectors for consistency, and reach for querySelectorAll when you need multiple matches.
03

The classic methods

Before querySelector existed, developers used a different set of methods. They still work, and getElementById is actually faster for ID lookups:

MethodReturnsLive?Best for
querySelector()First match or nullNoAny CSS selector
querySelectorAll()Static NodeListNoMultiple elements
getElementById()Element or null,Single ID (fastest)
getElementsByClassName()Live HTMLCollectionYesLegacy code
getElementsByTagName()Live HTMLCollectionYesLegacy code

"Live" means the collection updates automatically when the DOMWhat is dom?The Document Object Model - the browser's live representation of your HTML page as a tree of objects that JavaScript can read and modify. changes. Static (from querySelectorAll) is a snapshot, usually what you want.

04

Advanced selectors

The real power of querySelector comes from CSS selectors:

// Attribute selectors
const requiredFields = document.querySelectorAll('[required]');
const emailInputs = document.querySelectorAll('input[type="email"]');

// Pseudo-classes
const firstItem = document.querySelector('li:first-child');
const evenRows = document.querySelectorAll('tr:nth-child(even)');

// Combinators
const directChildren = document.querySelectorAll('ul > li');
const nextToActive = document.querySelector('.active + .item');
05

Scoping your queries

You can search within a specific element instead of the whole document:

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

// Search ONLY within the sidebar
const sidebarLinks = sidebar.querySelectorAll('a');
const sidebarTitle = sidebar.querySelector('h2');

This is more efficient and prevents accidentally selecting elements from other parts of the page.

06

Common mistakes

// Forgetting the dot for classes
document.querySelector('title');   // finds <title> tag
document.querySelector('.title');  // finds class="title"

// Forgetting the hash for IDs
document.querySelector('header');   // finds <header> tag
document.querySelector('#header');  // finds id="header"

// Treating NodeList like an array
const items = document.querySelectorAll('.item');
items.map(i => i.textContent);        // TypeError!
Array.from(items).map(i => i.textContent);  // works
07

Quick reference

TaskCodeReturns
Select by IDdocument.querySelector('#id')Element or null
Select by classdocument.querySelector('.class')First match or null
Select all by classdocument.querySelectorAll('.class')NodeList
Select by tagdocument.querySelector('tag')First match or null
Select within elementparent.querySelector('.child')Scoped match
Convert NodeListArray.from(nodeList)Real array
Null checkif (el) { ... }Prevents TypeError