Linux Professional Institute Learning Logo.
Skip to main content
  • Home
    • All Resources
    • LPI Learning Materials
    • Become a Contributor
    • Publishing Partners
    • Become a Publishing Partner
    • About
    • FAQ
    • Contributors
    • Roadmap
    • Contact
  • LPI.org
034.4 Lesson 1
Topic 031: Software Development and Web Technologies
031.1 Software Development Basic
  • 031.1 Lesson 1
031.2 Web Application Architecture
  • 031.2 Lesson 1
031.3 HTTP Basics
  • 031.3 Lesson 1
Topic 032: HTML Document Markup
032.1 HTML Document Anatomy
  • 032.1 Lesson 1
032.2 HTML Semantics and Document Hierarchy
  • 032.2 Lesson 1
032.3 HTML References and Embedded Resources
  • 032.3 Lesson 1
032.4 HTML Forms
  • 032.4 Lesson 1
Topic 033: CSS Content Styling
033.1 CSS Basics
  • 033.1 Lesson 1
033.2 CSS Selectors and Style Application
  • 033.2 Lesson 1
033.3 CSS Styling
  • 033.3 Lesson 1
033.4 CSS Box Model and Layout
  • 033.4 Lesson 1
Topic 034: JavaScript Programming
034.1 JavaScript Execution and Syntax
  • 034.1 Lesson 1
034.2 JavaScript Data Structures
  • 034.2 Lesson 1
034.3 JavaScript Control Structures and Functions
  • 034.3 Lesson 1
  • 034.3 Lesson 2
034.4 JavaScript Manipulation of Website Content and Styling
  • 034.4 Lesson 1
Topic 035: NodeJS Server Programming
035.1 NodeJS Basics
  • 035.1 Lesson 1
035.2 NodeJS Express Basics
  • 035.2 Lesson 1
  • 035.2 Lesson 2
035.3 SQL Basics
  • 035.3 Lesson 1
How to get certified
  1. Topic 034: JavaScript Programming
  2. 034.4 JavaScript Manipulation of Website Content and Styling
  3. 034.4 Lesson 1

034.4 Lesson 1

Certificate:

Web Development Essentials

Version:

1.0

Topic:

034 JavaScript Programming

Objective:

034.4 JavaScript Manipulation of Website Content and Styling

Lesson:

1 of 1

Introduction

HTML, CSS, and JavaScript are three distinct technologies that come together on the Web. In order to make truly dynamic and interactive pages, the JavaScript programmer must combine components from HTML and CSS at run time, a task that is greatly facilitated by using the Document Object Model (DOM).

Interacting with the DOM

The DOM is a data structure that works as a programming interface to the document, where every aspect of the document is represented as a node in the DOM and every change made to the DOM will immediately reverberate in the document. To show how to use the DOM in JavaScript, save the following HTML code in a file called example.html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>HTML Manipulation with JavaScript</title>
</head>
<body>

<div class="content" id="content_first">
<p>The dynamic content goes here</p>
</div><!-- #content_first -->

<div class="content" id="content_second" hidden>
<p>Second section</p>
</div><!-- #content_second -->

</body>
</html>

The DOM will be available only after the HTML is loaded, so write the following JavaScript at the end of the page body (before the ending </body> tag):

<script>
let body = document.getElementsByTagName("body")[0];
console.log(body.innerHTML);
</script>

The document object is the top DOM element, all other elements branch off from it. The getElementsByTagName() method lists all the elements descending from document that have the given tag name. Even though the body tag is used only once in the document, the getElementsByTagName() method always return an array-like collection of found elements, hence the use of the [0] index to return the first (and only) element found.

HTML Content

As shown in the previous example, the DOM element returned by the document.getElementsByTagName("body")[0] was assigned to the body variable. The body variable can then be used to manipulate the page’s body element, because it inherits all the DOM methods and attributes from that element. For instance, the innerHTML property contains the entire HTML markup code written inside the corresponding element, so it can be used to read the inner markup. Our console.log(body.innerHTML) call prints the content inside <body></body> to the web console. The variable can also be used to replace that content, as in body.innerHTML = "<p>Content erased</p>".

Rather than changing entire portions of HTML markup, it is more practical to keep the document structure unaltered and just interact with its elements. Once the document is rendered by the browser, all the elements are accessible by DOM methods. It is possible, for example, to list and access all the HTML elements using the special string * in the getElementsByTagName() method of the document object:

let elements = document.getElementsByTagName("*");
for ( element of elements )
{
  if ( element.id == "content_first" )
  {
    element.innerHTML = "<p>New content</p>";
  }
}

This code will place all the elements found in document in the elements variable. The elements variable is an array-like object, so we can iterate through each of its items with a for loop. If the HTML page where this code runs has an element with an id attribute set to content_first (see the sample HTML page shown at the start of the lesson), the if statement matches that element and its markup contents will be changed to <p>New content</p>. Note that the attributes of an HTML element in the DOM are accessible using the dot notation of JavaScript object properties: therefore, element.id refers to the id attribute of the current element of the for loop. The getAttribute() method could also be used, as in element.getAttribute("id").

It is not necessary to iterate through all the elements if you want to inspect only a subset of them. For example, the document.getElementsByClassName() method limits the matched elements to those having a specific class:

let elements = document.getElementsByClassName("content");
for ( element of elements )
{
  if ( element.id == "content_first" )
  {
    element.innerHTML = "<p>New content</p>";
  }
}

However, iterating through many document elements using a loop is not the best strategy when you have to change a specific element in the page.

Selecting Specific Elements

JavaScript provides optimized methods to select the exact element you want to work on. The previous loop could be entirely replaced by the document.getElementById() method:

let element = document.getElementById("content_first");
element.innerHTML = "<p>New content</p>";

Every id attribute in the document must be unique, so the document.getElementById() method returns only a single DOM object. Even the declaration of the element variable can be omitted, because JavaScript lets us chain methods directly:

document.getElementById("content_first").innerHTML = "<p>New content</p>";

The getElementById() method is the preferable method to locate elements in the DOM, because its performance is much better than iterative methods when working with complex documents. However, not all elements have an explicit ID, and the method returns a null value if no element matches with the provided ID (this also prevents the use of chained attributes or functions, like the innerHTML used in the example above). Moreover, it is more practical to assign ID attributes only to the main components of the page and then use CSS selectors to locate their child elements.

Selectors, introduced in an earlier lesson on CSS, are patterns that match elements in the DOM. The querySelector() method returns the first matching element in the DOM’s tree, while querySelectorAll() returns all elements that match the specified selector.

In the previous example, the getElementById() method retrieves the element bearing the content_first ID. The querySelector() method can perform the same task:

document.querySelector("#content_first").innerHTML = "<p>New content</p>";

Because the querySelector() method uses selector syntax, the provided ID must begin with a hash character. If no matching element is found, the querySelector() method returns null.

In the previous example, the entire content of the content_first div is replaced by the text string provided. The string has HTML code in it, which is not considered a best practice. You must be careful when adding hard-coded HTML markup to JavaScript code, because tracking elements can become difficult when changes to the overall document structure are required.

Selectors are not restricted to the ID of the element. The internal p element can be addressed directly:

document.querySelector("#content_first p").innerHTML = "New content";

The #content_first p selector will match only the first p element inside the #content_first div. It works fine if we want to manipulate the first element. However, we may want to change the second paragraph:

<div class="content" id="content_first">
<p>Don't change this paragraph.</p>
<p>The dynamic content goes here.</p>
</div><!-- #content_first -->

In this case, we can use the :nth-child(2) pseudo-class to match the second p element:

document.querySelector("#content_first p:nth-child(2)").innerHTML = "New content";

The number 2 in p:nth-child(2) indicates the second paragraph that matches the selector. See the CSS selectors lesson to know more about selectors and how to use them.

Working with Attributes

JavaScript’s ability to interact with the DOM is not restricted to content manipulation. Indeed, the most pervasive use of JavaScript in the browser is to modify the attributes of the existing HTML elements.

Let’s say our original HTML example page has now three sections of content:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>HTML Manipulation with JavaScript</title>
</head>
<body>

<div class="content" id="content_first" hidden>
<p>First section.</p>
</div><!-- #content_first -->

<div class="content" id="content_second" hidden>
<p>Second section.</p>
</div><!-- #content_second -->

<div class="content" id="content_third" hidden>
<p>Third section.</p>
</div><!-- #content_third -->

</body>
</html>

You may want to make only one of them visible at a time, hence the hidden attribute in all div tags. This is useful, for example, to show only one image from a gallery of images. To make one of them visible when the page loads, add the following JavaScript code to the page:

// Which content to show
let content_visible;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_visible = "#content_first";
  break;
  case 1:
    content_visible = "#content_second";
  break;
  case 2:
    content_visible = "#content_third";
  break;
}

document.querySelector(content_visible).removeAttribute("hidden");

The expression evaluated by the switch statement randomly returns the number 0, 1, or 2. The corresponding ID selector is then be assigned to the content_visible variable, which is used by the querySelector(content_visible) method. The chained removeAttribute("hidden") call removes the hidden attribute from the element.

The opposite approach is also possible: All sections could be initially visible (without the hidden attribute) and the JavaScript program can then assign the hidden attribute to every section except the one in content_visible. To do so, you must iterate through all the content div elements that are different from the chosen one, which can be done by using the querySelectorAll() method:

// Which content to show
let content_visible;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_visible = "#content_first";
  break;
  case 1:
    content_visible = "#content_second";
  break;
  case 2:
    content_visible = "#content_third";
  break;
}

// Hide all content divs, except content_visible
for ( element of document.querySelectorAll(".content:not("+content_visible+")") )
{
  // Hidden is a boolean attribute, so any value will enable it
  element.setAttribute("hidden", "");
}

If the content_visible variable was set to #content_first, the selector will be .content:not(#content_first), which reads as all elements having the content class except those having the content_first ID. The setAttribute() method adds or changes attributes of HTML elements. Its first parameter is the name of the attribute and the second is the value of the attribute.

However, the proper way to change the appearance of elements is with CSS. In this case, we can set the display CSS property to hidden and then change it to block using JavaScript:

<style>
div.content { display: none }
</style>

<div class="content" id="content_first">
<p>First section.</p>
</div><!-- #content_first -->

<div class="content" id="content_second">
<p>Second section.</p>
</div><!-- #content_second -->

<div class="content" id="content_third">
<p>Third section.</p>
</div><!-- #content_third -->

<script>
// Which content to show
let content_visible;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_visible = "#content_first";
  break;
  case 1:
    content_visible = "#content_second";
  break;
  case 2:
    content_visible = "#content_third";
  break;
}
document.querySelector(content_visible).style.display = "block";
</script>

The same good practices that apply to mixing HTML tags with JavaScript apply also to CSS. Thus, writing CSS properties directly in JavaScript code is not recommended. Instead, CSS rules should be written apart from JavaScript code. The proper way to alternate visual styling is to select a pre-defined CSS class for the element.

Working with Classes

Elements may have more than one associated class, making it easier to write styles that can be added or removed when necessary. It would be exhausting to change many CSS attributes directly in JavaScript, so you can create a new CSS class with those attributes and then add the class to the element. DOM elements have the classList property, which can be used to view and manipulate the classes assigned to the corresponding element.

For example, instead of changing the visibility of the element, we can create an additional CSS class to highlight our content div:

div.content {
  border: 1px solid black;
  opacity: 0.25;
}
div.content.highlight {
  border: 1px solid red;
  opacity: 1;
}

This stylesheet will add a thin black border and semi-transparency to all elements having the content class. Only the elements that also have the highlight class will be fully opaque and have the thin red border. Then, instead of changing the CSS properties directly as we did before, we can use the classList.add("highlight") method in the selected element:

// Which content to highlight
let content_highlight;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_highlight = "#content_first";
  break;
  case 1:
    content_highlight = "#content_second";
  break;
  case 2:
    content_highlight = "#content_third";
  break;
}

// Highlight the selected div
document.querySelector(content_highlight).classList.add("highlight");

All the techniques and examples we have seen so far were performed at the end of the page loading process, but they are not restricted to this stage. In fact, what makes JavaScript so useful to Web developers is its ability to react to events on the page, which we will see next.

Event Handlers

All visible page elements are susceptible to interactive events, such as the click or the movement of the mouse itself. We can associate custom actions to these events, which greatly expands what an HTML document can do.

Probably the most obvious HTML element that benefits from an associated action is the button element. To show how it works, add three buttons above the first div element of the example page:

<p>
<button>First</button>
<button>Second</button>
<button>Third</button>
</p>

<div class="content" id="content_first">
<p>First section.</p>
</div><!-- #content_first -->

<div class="content" id="content_second">
<p>Second section.</p>
</div><!-- #content_second -->

<div class="content" id="content_third">
<p>Third section.</p>
</div><!-- #content_third -->

The buttons do nothing on their own, but suppose you want to highlight the div corresponding to the pressed button. We can use the onClick attribute to associate an action to each button:

<p>
<button onClick="document.getElementById('content_first').classList.toggle('highlight')">First</button>
<button onClick="document.getElementById('content_second').classList.toggle('highlight')">Second</button>
<button onClick="document.getElementById('content_third').classList.toggle('highlight')">Third</button>
</p>

The classList.toggle() method adds the specified class to the element if it is not present, and removes that class if it is already present. If you run the example, you will note that more than one div can be highlighted at the same time. To highlight only the div corresponding to the pressed button, it is necessary to remove the highlight class from the other div elements. Nonetheless, if the custom action is too long or involves more than one line of code, it’s more practical to write a function apart from the element tag:

function highlight(id)
{
  // Remove the "highlight" class from all content elements
  for ( element of document.querySelectorAll(".content") )
  {
    element.classList.remove('highlight');
  }

  // Add the "highlight" class to the corresponding element
  document.getElementById(id).classList.add('highlight');
}

Like the previous examples, this function can be placed inside a <script> tag or in an external JavaScript file associated with the document. The highlight function first removes the highlight class from all the div elements associated with the content class, then adds the highlight class to the chosen element. Each button should then call this function from its onClick attribute, using the corresponding ID as the function’s argument:

<p>
<button onClick="highlight('content_first')">First</button>
<button onClick="highlight('content_second')">Second</button>
<button onClick="highlight('content_third')">Third</button>
</p>

In addition to the onClick attribute, we could use the onMouseOver attribute (triggered when the pointing device is used to move the cursor onto the element), the onMouseOut attribute (triggered when the pointing device is no longer contained within the element), etc. Moreover, event handlers are not restricted to buttons, so you can assign custom actions to these event handlers for all visible HTML elements.

Guided Exercises

  1. Using the document.getElementById() method, how could you insert the phrase “Dynamic content” to the inner content of the element whose ID is message?

  2. What is the difference between referencing an element by its ID using the document.querySelector() method and doing so via the document.getElementById() method?

  3. What is the purpose of the classList.remove() method?

  4. What is the result of using the method myelement.classList.toggle("active") if myelement does not have the active class assigned to it?

Explorational Exercises

  1. What argument to the document.querySelectorAll() method will make it mimic the document.getElementsByTagName("input") method?

  2. How can you use the classList property to list all the classes associated with a given element?

Summary

This lesson covers how to use JavaScript to change HTML contents and their CSS properties using the DOM (Document Object Model). These changes can be triggered by user events, which is useful to create dynamic interfaces. The lesson goes through the following concepts and procedures:

  • How to inspect the structure of the document using methods like document.getElementById(), document.getElementsByClassName(), document.getElementsByTagName(), document.querySelector() and document.querySelectorAll().

  • How to change the document’s content with the innerHTML property.

  • How to add and modify the attributes of page elements with methods setAttribute() and removeAttribute().

  • The proper way to manipulate elements classes using the classList property and its relation to CSS styles.

  • How to bind functions to mouse events in specific elements.

Answers to Guided Exercises

  1. Using the document.getElementById() method, how could you insert the phrase “Dynamic content” to the inner content of the element whose ID is message?

    It can be done with the innerHTML property:

    document.getElementById("message").innerHTML = "Dynamic content"
  2. What is the difference between referencing an element by its ID using the document.querySelector() method and doing so via the document.getElementById() method?

    The ID must be accompanied by the hash character in functions that use selectors, such as document.querySelector().

  3. What is the purpose of the classList.remove() method?

    It removes the class (whose name is given as the argument of the function) from the class attribute of the corresponding element.

  4. What is the result of using the method myelement.classList.toggle("active") if myelement does not have the active class assigned to it?

    The method will assign the active class to myelement.

Answers to Explorational Exercises

  1. What argument to the document.querySelectorAll() method will make it mimic the document.getElementsByTagName("input") method?

    Using document.querySelectorAll("input") will match all the input elements in the page, just like document.getElementsByTagName("input").

  2. How can you use the classList property to list all the classes associated with a given element?

    The classList property is an array-like object, so a for loop can be used to iterate through all the classes it contains.

Linux Professional Insitute Inc. All rights reserved. Visit the Learning Materials website: https://learning.lpi.org
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

Next Lesson

035.1 NodeJS Basics (035.1 Lesson 1)

Read next lesson

Linux Professional Insitute Inc. All rights reserved. Visit the Learning Materials website: https://learning.lpi.org
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

LPI is a non-profit organization.

© 2023 Linux Professional Institute (LPI) is the global certification standard and career support organization for open source professionals. With more than 200,000 certification holders, it's the world’s first and largest vendor-neutral Linux and open source certification body. LPI has certified professionals in over 180 countries, delivers exams in multiple languages, and has hundreds of training partners.

Our purpose is to enable economic and creative opportunities for everybody by making open source knowledge and skills certification universally accessible.

  • LinkedIn
  • flogo-RGB-HEX-Blk-58 Facebook
  • Twitter
  • Contact Us
  • Privacy and Cookie Policy

Spot a mistake or want to help improve this page? Please let us know.

© 1999–2023 The Linux Professional Institute Inc. All rights reserved.