What you'll learn
- Select and change elements on a page
- Use querySelector and querySelectorAll with CSS selectors
- Change text with textContent and classes with classList
- Explain why textContent is safer than innerHTML for untrusted data
Find elements on a page with querySelector and change their text, classes and attributes.
Why this matters
HTML describes what is on a page; CSS describes how it looks. JavaScript makes it change: a counter going up, a menu opening, an error message appearing under a form field. To change anything, you first have to get hold of it. This lesson is about finding elements on a page and editing them, which is step one of every interactive feature you will build.
The DOM
When the browser loads your HTML, it builds a tree of objects in memory called the DOMThe Document Object Model: the browser's live tree of objects for the page, which JavaScript reads and edits through document. (Document Object Model). Every tag becomes a node in that tree, and JavaScript can read and edit those nodes. The entry point is the global document object.
<body>
<h1 id="title">My shop</h1>
<p class="intro">Welcome!</p>
<ul>
<li class="item">Pens</li>
<li class="item">Paper</li>
</ul>
</body>Change the DOM and the page updates straight away; you never edit the HTML file itself.
querySelector and querySelectorAll
Both take a CSS selector, the same syntax you already know from stylesheets:
const title = document.querySelector("#title"); // by id
const intro = document.querySelector(".intro"); // first match by class
const firstItem = document.querySelector("ul li"); // descendant selector
const items = document.querySelectorAll(".item"); // ALL matchesquerySelectorreturns the first matching element, ornullif nothing matches.querySelectorAllreturns a NodeListThe list of elements returned by querySelectorAll, which you can loop over with for...of or forEach. of every match (possibly empty). You can loop over it withfor...oforforEach.
for (const item of items) {
console.log(item.textContent);
}
items.length; // 2You may also meet older methods such as getElementById("title") and getElementsByClassName("item"). They work, but querySelector covers every case with one consistent syntax.
Changing what is on the page
Once you have an element, you can change it:
title.textContent = "Spring sale"; // replace the text
intro.style.color = "darkgreen"; // set one inline style
title.setAttribute("data-state", "sale"); // set any attribute
const link = document.querySelector("a");
link.href = "https://example.com"; // common attributes are propertiestextContent vs innerHTML
textContent sets plain text. innerHTML parses the string as HTML:
intro.textContent = "<b>Hi</b>"; // shows the characters <b>Hi</b>
intro.innerHTML = "<b>Hi</b>"; // shows bold HiUse textContent for anything that came from a user or a server. Putting untrusted text into innerHTML lets someone inject their own HTML and scripts into your page, a security hole called cross-site scripting (XSS)A security hole where untrusted text inserted as HTML lets someone run their own scripts on your page.. Use innerHTML only for markup you wrote yourself.
Classes are better than inline styles
Rather than setting lots of style properties, define a class in CSS and switch it on and off with classList:
.highlight { background: #fff3b0; }firstItem.classList.add("highlight");
firstItem.classList.remove("highlight");
firstItem.classList.toggle("highlight"); // add if missing, remove if present
firstItem.classList.contains("highlight"); // true or falseThis keeps styling in CSS where it belongs, and one class can change many properties at once.
A worked example
Mark every item and show a count:
const items = document.querySelectorAll(".item");
for (const item of items) {
item.classList.add("highlight");
}
document.querySelector(".intro").textContent =
`There are ${items.length} items`;Where to put your script
A script can only select elements that already exist. If your <script> is in the <head>, the body has not been built yet and querySelector returns null. Two fixes:
- Put the
<script>at the end of the<body>(what this course does), or - Use
<script src="app.js" defer></script>in the head, which waits until the page is parsed.
Common mistakes
- Forgetting the
#or.querySelector("title")looks for a<title>tag, notid="title". - Using the result of
querySelectorwithout checking it. If it isnull,title.textContent = ...throws "Cannot set properties of null". Check your selector in the console. - Treating a NodeList like one element.
items.textContent = "x"does nothing useful; loop over the items. - Running the script before the elements exist. Move it to the end of the body or use
defer. - Using
innerHTMLwith user input. UsetextContent.
Quick recap
- The DOM is the browser's live tree of your page;
documentis the way in. querySelectorreturns the first match ornull;querySelectorAllreturns all matches.- Change text with
textContent, classes withclassList, attributes with properties orsetAttribute. - Prefer classes over inline styles and
textContentoverinnerHTML.
Try it
Open the Do tab. A small shop page is ready; you will write the JavaScript that changes its title, highlights every item and shows the item count.
Key terms (6)
- DOM
- The Document Object Model: the browser's live tree of objects for the page, which JavaScript reads and edits through document.
- querySelector
- A method that returns the first element matching a CSS selector, or null when nothing matches.
- NodeList
- The list of elements returned by querySelectorAll, which you can loop over with for...of or forEach.
- textContent
- A property holding an element's plain text; setting it shows the string as text, never as HTML.
- classList
- An element property with add, remove, toggle and contains methods for switching CSS classes.
- cross-site scripting (XSS)
- A security hole where untrusted text inserted as HTML lets someone run their own scripts on your page.