Skip to content
beginner

Practical DOM Examples

You have learned how to select elements, change their content, update their styles, and create new elements from scratch. Each of those skills makes sense…

Published 2026-09-06Updated 2026-09-1210 min read
A vast desert landscape featuring acacia and palm trees under a clear blue sky.
A vast desert landscape featuring acacia and palm trees under a clear blue sky. Photo by French Sweetie on Pexels.

You have learned how to select elements, change their content, update their styles, and create new elements from scratch. Each of those skills makes sense on its own. This article is where they stop being separate facts and start working together.

We are going to build three small, runnable projects. Each one combines the DOM skills you already know into something that actually does a job in the browser. By the end, you will have written code that responds to clicks, hides and shows content, and builds new page elements on demand.

What You'll Build and What You Need First

This is a practice article, not a new theory lesson. You will be combining skills from earlier tutorials:

  • Selecting elements with querySelector or getElementById
  • Changing text with textContent
  • Updating styles with classList or the style property
  • Creating and removing elements with createElement and append

If you need a refresher on creating elements, go back to the Creating and Removing Elements lesson before starting. The projects here assume you can already do each individual step. What they teach is how to chain those steps together.

Here is what you will build:

  1. A button that changes its own text — practices selecting, listening for clicks, and updating content.
  2. A message that appears and disappears — practices toggling visibility and updating styles.
  3. Add items to a list — practices creating elements, appending them, and clearing an input.

Setting Up Your Practice Files

Each project below is self-contained. The starter HTML and the solution include everything that project needs, and the projects are designed to be run one at a time.

The simplest approach: create one HTML file per project. Name them something like project1.html, project2.html, and project3.html. Open whichever one you are currently practicing in your browser.

If you prefer to use a single file, replace the previous project's content when you move to the next one. Do not paste all three projects into the same file. They use the same element ids in places, and combining them can cause confusing behavior that has nothing to do with the skill you are practicing.

Use this as your starting skeleton for each file:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>DOM Practice</title>
</head>
<body>
  <!-- Your project HTML goes here -->

  <script>
    // Your JavaScript goes here
  </script>
</body>
</html>

The script tag sits at the end of the body. That way, the browser has already created all the elements on the page before your JavaScript runs. Save the file, open it in your browser, and you are ready to practice.

Project 1: A Button That Changes Its Own Text

A flowchart showing three examples converging on the same pattern: a click or typed input triggers JavaScript; JavaScript selects or creates an element, changes text, visibility, or list contents, and the browser displays the updated page.
All three projects follow the same DOM pattern: respond to an action, update an element, and let the browser render the change.

Goal: Click a button and watch its label change.

This is the smallest possible win: one element, one click, one change. It proves you can connect a user action to a DOM update.

Starter HTML

<button id="action-button">Click me</button>

Expected Behavior

When you load the page, the button reads "Click me." When you click it, the label changes to "You clicked me!" That is the entire project.

Hint

You need three steps: grab the button with getElementById, attach a click listener with addEventListener, and update the button's textContent inside the listener.

The Solution

<button id="action-button">Click me</button>

<script>
  const button = document.getElementById("action-button");

  button.addEventListener("click", () => {
    button.textContent = "You clicked me!";
  });
</script>

How It Works

The first line selects the button and stores a reference to it in the button variable. The second line tells the browser: "When this button gets clicked, run this function." Inside that function, textContent replaces the button's current label with the new one.

Notice that we used textContent, not innerHTML. For plain text, textContent is the safe choice. It treats the string as text, not as HTML. If you ever set textContent to something a user typed, it cannot accidentally break your page or create a security hole. innerHTML parses strings as HTML, which is powerful but risky. For labels, messages, and user input, make textContent your default.

Knowledge check

Check your understanding

Answer this question before you continue.

In Project 1, what should the click listener change to update the button label?
Single Choice

Focus: Use a click listener and textContent to change an element's visible text.

Optional Extension

Make the button toggle between two labels. Each click flips it to the other one. A simple way is to check the current label and choose the opposite:

button.addEventListener("click", () => {
  if (button.textContent === "Click me") {
    button.textContent = "You clicked me!";
  } else {
    button.textContent = "Click me";
  }
});

Project 2: A Message That Appears and Disappears

Goal: A button that shows or hides a paragraph, and changes its own label to match.

This project adds styling to the mix. You are not just changing text anymore. You are controlling whether an element is visible at all.

Starter HTML

<p id="message" class="hidden">This is a secret message.</p>
<button id="toggle-button">Show message</button>

Add this small CSS rule inside a <style> tag in your <head>:

.hidden {
  display: none;
}

Expected Behavior

When the page loads, the message is invisible. The button reads "Show message." Click it once, and the message appears while the button changes to "Hide message." Click again, and the message disappears while the button changes back.

Knowledge check

Check your understanding

Answer this question before you continue.

The message starts with the hidden class and the button says "Show message." After one click, what happens?
Output Prediction

Focus: Predict the visibility and button-label changes caused by toggling a CSS class.

The hidden class uses display: none, and the click handler toggles that class before checking whether it is still present.

Hint

The classList.toggle method adds a class if it is missing and removes it if it is present. That is exactly the on-off behavior you want.

The Solution

<style>
  .hidden {
    display: none;
  }
</style>

<p id="message" class="hidden">This is a secret message.</p>
<button id="toggle-button">Show message</button>

<script>
  const message = document.getElementById("message");
  const toggleButton = document.getElementById("toggle-button");

  toggleButton.addEventListener("click", () => {
    message.classList.toggle("hidden");

    if (message.classList.contains("hidden")) {
      toggleButton.textContent = "Show message";
    } else {
      toggleButton.textContent = "Hide message";
    }
  });
</script>

How It Works

The hidden class applies display: none, which removes the element from the page layout entirely. When you toggle that class on and off, the element appears and disappears cleanly.

Why use a class instead of inline styles? Imagine you set message.style.display = "none" directly in JavaScript. Later, you want to change how the message is hidden, maybe with a fade-out animation. You would have to find and update that JavaScript line. With a class, you only change the CSS rule, and every place that toggles the class automatically uses the new behavior. Keeping styles in CSS and using JavaScript to flip classes is a cleaner separation.

Optional Extension

Change the message color each time it appears. You can pick from a small array of colors and cycle through them:

const colors = ["tomato", "steelblue", "seagreen"];
let colorIndex = 0;

// Inside the click listener, after showing the message:
message.style.color = colors[colorIndex];
colorIndex = (colorIndex + 1) % colors.length;

Project 3: Add Items to a List

Goal: Type into an input, click a button, and see the item appear in a list.

This is the project where everything comes together. You read a value, create a new element, add it to the page, and clear the input for the next entry.

Starter HTML

<input type="text" id="item-input" placeholder="Type something...">
<button id="add-button">Add item</button>
<ul id="item-list"></ul>

Expected Behavior

Type "learn JavaScript" into the input. Click the button. The text "learn JavaScript" appears as a list item. The input clears itself, ready for the next entry. Click again with a new value, and a second item appears below the first.

Hint

Read the input's value property, create an li with createElement, set its textContent, and append it to the ul with append. Then set the input's value back to an empty string.

The Solution

<input type="text" id="item-input" placeholder="Type something...">
<button id="add-button">Add item</button>
<ul id="item-list"></ul>

<script>
  const input = document.getElementById("item-input");
  const addButton = document.getElementById("add-button");
  const list = document.getElementById("item-list");

  addButton.addEventListener("click", () => {
    const itemText = input.value.trim();

    if (itemText === "") {
      return;
    }

    const listItem = document.createElement("li");
    listItem.textContent = itemText;
    list.append(listItem);

    input.value = "";
    input.focus();
  });
</script>

How It Works

The trim() method removes extra spaces from the start and end of the input. If the user typed only spaces, itemText becomes an empty string, and the return statement stops the function before adding anything. That guard prevents a list full of blank items.

Then the real work happens in three lines:

  1. createElement("li") builds a new list item that exists only in JavaScript, not yet on the page.
  2. textContent puts the user's text inside it.
  3. list.append(listItem) attaches it to the <ul>, and the browser renders it.

Finally, clearing the input and calling focus() puts the cursor back in the text field. The user can immediately type the next item without clicking anywhere.

Why createElement plus textContent instead of building an HTML string with innerHTML? Because textContent treats user input as plain text. If someone types <b>hello</b>, it appears as literal text, not as bold formatting. With innerHTML, that same input would be parsed as HTML, which can break your layout or worse. When the content comes from a user, always use textContent.

Knowledge check

Check your understanding

Answer this question before you continue.

Which sequence safely adds the user's text as a new list item?
Single Choice

Focus: Create a list item from user input while keeping the input as plain text.

Optional Extension

Let the Enter key add an item too. Listen for the keydown event on the input, and check whether the pressed key is Enter:

input.addEventListener("keydown", (event) => {
  if (event.key === "Enter") {
    addButton.click();
  }
});

Calling addButton.click() runs the same code as a real button click, so you do not have to duplicate the logic.

Common Mistakes to Watch For

These are the errors beginners hit most often when combining DOM skills. Each one has a clear symptom and a simple fix.

Script runs before the elements exist

Symptom: Your JavaScript does nothing, and the browser console shows an error like Cannot read properties of null.

Cause: Your script ran before the browser finished building the page, so the element you tried to select did not exist yet.

Fix: Put your <script> tag at the end of the <body>, right before the closing tag. By then, every element above it has been created.

Selecting an element that doesn't exist

Symptom: document.querySelector("#wrong-id") returns null, and calling any method on it throws an error.

Cause: The id or selector does not match anything on the page. A typo in the id, or selecting before the element exists, both produce this.

Fix: Check the id in your HTML matches the id in your JavaScript exactly. Ids are case-sensitive.

Forgetting to clear the input

Symptom: You add "milk" to the list, and the text stays in the input. Click again, and "milk" gets added a second time.

Cause: The input's value was never reset after adding the item.

Fix: Set input.value = "" at the end of your click handler.

Knowledge check

Check your understanding

Answer this question before you continue.

A list app adds the current input value each time the button is clicked, but the input still contains the old value afterward. Which fix addresses this symptom?
Debugging

Focus: Diagnose and fix repeated list entries caused by failing to reset an input.

The item is appended successfully, but the click handler does not change the input after adding it.

Using innerHTML with user input

Symptom: A user types something with HTML tags, and the page renders it as formatting instead of text. In the worst case, the page breaks or becomes a security risk.

Cause: innerHTML parses strings as HTML.

Fix: Use textContent whenever the content could come from a user.

What to Practice Next

Here is your next challenge: combine all three projects into one small page. Build a simple to-do list where each item has its own remove button. You will need to create list items, append them, and attach a click listener to each remove button as you create it. That is the natural next step after these three projects, and it is exactly the kind of feature that appears in real web apps everywhere.

If you get stuck, read the error message in the browser console first. The console tells you which line failed and why. Debugging these small projects is not a detour from learning. It is the practice that makes the skills automatic.

Every project in this article relied on click listeners. That is the thread connecting them all, and it points to your next topic: events. Understanding how events work, how to listen for them, and how to respond to them will let you build pages that feel alive. When you are ready, move on to events, and bring these DOM skills with you.

Knowledge check

Final check

Finish the article by checking the ideas you just learned.

What does the Project 3 solution do when the user enters only spaces and clicks Add item?
Question 1 of 2Output Prediction

Focus: Predict how the trim-and-return guard handles input containing only spaces.

The handler computes itemText = input.value.trim(); then checks if (itemText === "") { return; } before creating a list item.
A user types `<b>hello</b>` and you want those characters to appear literally in a newly created element. Which choice matches the article's safe approach?
Question 2 of 2Misconception Check

Focus: Choose the DOM API that keeps user-provided content as literal text instead of parsing it as HTML.

References

  1. DOM scripting introduction - Learn web development | MDNdeveloper.mozilla.org
  2. DOM Manipulation and Eventswww.theodinproject.com
8sources checked
8source domains
5searches run

Research updated Sep 6, 2026

Keep learning

Related tutorials

Continue with nearby JavaScript topics and beginner-friendly explanations.

From above of surface of wavy blue sea on sunny day as background
beginner
8 min read

Changing DOM Content

A static page is a finished product. A dynamic page is a conversation: the user clicks, submits, or types, and the page answers. That answer usually means…

Read tutorial
A stunning view of a bright blue sky filled with fluffy clouds, capturing a serene and peaceful atmosphere.
beginner
8 min read

Creating and Removing Elements

A static HTML page is frozen the moment it loads. Real sites keep changing after that—a to-do item appears, a cart entry disappears, a new message slides…

Read tutorial