JavaScript DOM Basics: querySelector and createElement

This article explains the two DOM methods most beginners need first: querySelector for finding elements and createElement for building new ones. You will learn how these methods work together to read, create, and insert content in the browser.

Quick answer: Use document.querySelector() to select the first element that matches a CSS selector, and use document.createElement() to make a new element before adding it to the page with appendChild() or append().

Difficulty: Beginner

You'll understand this better if you know: basic JavaScript variables, functions, and how HTML elements are structured in the browser.

1. What Is DOM Basics?

The DOM, or Document Object Model, is the browser’s live representation of your HTML page. DOM basics means learning how JavaScript can find existing elements, read their content, change their attributes, and create new nodes.

2. Why DOM Basics Matter

Most interactive web pages need JavaScript to respond to clicks, display messages, update lists, or show fetched data. DOM basics are the foundation for all of that work.

Without these methods, you cannot reliably connect your JavaScript code to the page structure. With them, you can build features like menus, alerts, tabs, counters, forms, and live search results.

3. Basic Syntax or Core Idea

Using querySelector to find an element

querySelector takes a CSS selector string and returns the first matching element. If nothing matches, it returns null.

const button = document.querySelector(".save-button");

This code looks for the first element with the class save-button and stores it in button.

Using createElement to make a new element

createElement creates an element in memory, but it does not show up on the page until you insert it into the DOM.

const item = document.createElement("li");

This creates a new list item element that you can configure before inserting it.

Adding content to the new element

After creating an element, you can set text, attributes, and classes before attaching it to the page.

const item = document.createElement("li");item.textContent = "New task";item.classList.add("task");

This is the core pattern: create first, then configure, then insert.

4. Step-by-Step Examples

Example 1: Select a paragraph and change its text

This example shows the simplest use of querySelector. You find one element and update it directly.

const message = document.querySelector(".message");if (message) {  message.textContent = "Saved successfully.";}

The if check matters because querySelector can return null.

Example 2: Create a button and configure it

This example builds a button from scratch, then adds text and an attribute.

const button = document.createElement("button");button.textContent = "Click me";button.setAttribute("type", "button");

The button exists in memory now, but it is still not visible until you insert it somewhere.

Example 3: Add a new list item to an existing list

This is one of the most common DOM tasks. First, find the list; then create the item; then append it.

const list = document.querySelector("#shopping-list");const item = document.createElement("li");item.textContent = "Milk";if (list) {  list.appendChild(item);}

This inserts one new list item into the selected list only if the list exists.

Example 4: Use querySelector on a container, not just the document

You do not always need to search the whole page. You can search inside a specific section to keep code focused and avoid accidental matches.

const card = document.querySelector(".profile-card");const name = card ? card.querySelector("h2") : null; if (name) {  name.textContent = "Updated name";}

This pattern is useful when the page contains repeated components with similar structure.

5. Practical Use Cases

6. Common Mistakes

Mistake 1: Assuming querySelector finds every match

querySelector returns only the first matching element, not all of them. Beginners often expect every matched item to update at once.

Problem: This code changes only one item because querySelector does not return a collection.

const item = document.querySelector(".todo");item.classList.add("done");

Fix: Use querySelectorAll when you need every matching element.

const items = document.querySelectorAll(".todo");items.forEach((item) => {  item.classList.add("done");});

The corrected version works because querySelectorAll returns a list you can loop over.

Mistake 2: Forgetting that querySelector can return null

If no element matches the selector, the result is null. Trying to read a property from null causes a runtime error.

Problem: When the element is missing, this code throws Cannot read properties of null.

const title = document.querySelector(".page-title");title.textContent = "Welcome";

Fix: Check the value before using it, or make sure the selector is correct.

const title = document.querySelector(".page-title");if (title) {  title.textContent = "Welcome";}

The fixed version avoids the null reference and only runs when the element is present.

Mistake 3: Creating an element but never inserting it

createElement only makes a node in memory. If you never append it, the user will never see it.

Problem: This code builds a heading but does not attach it to the DOM, so nothing appears on the page.

const heading = document.createElement("h2");heading.textContent = "Latest News";

Fix: Append the new node to a container after configuring it.

const heading = document.createElement("h2");heading.textContent = "Latest News";const section = document.querySelector("#news");if (section) {  section.appendChild(heading);}

The corrected version works because the element becomes part of the rendered page.

7. Best Practices

Practice 1: Cache selectors you use more than once

If you need the same element repeatedly, store the result instead of querying the DOM again and again. This keeps your code clearer and avoids unnecessary work.

const counter = document.querySelector(".counter");if (counter) {  counter.textContent = "10";}

This is better than repeating the same selector in multiple lines of code.

Practice 2: Prefer textContent for plain text

Use textContent when you only need text, not HTML. It is simpler and safer for user-generated content.

const label = document.createElement("p");label.textContent = "Hello, world!";

This avoids parsing markup and keeps the content predictable.

Practice 3: Build elements before inserting them

Set classes, text, and attributes on a node before appending it. That way the user sees the final version immediately instead of a partially built element.

const tag = document.createElement("span");tag.classList.add("badge");tag.textContent = "New";

Preparing the node first helps avoid flicker and makes the DOM update cleaner.

8. Limitations and Edge Cases

9. Practical Mini Project

Here is a small example that finds a list and a button, creates a new task item, and adds it to the page when the user clicks the button.

const list = document.querySelector("#task-list");const button = document.querySelector("#add-task");if (list && button) {  button.addEventListener("click", () => {    const item = document.createElement("li");    item.textContent = "New task";    list.appendChild(item);  });}

This example shows the full workflow: select existing elements, create a new node, and insert it into the document in response to a user action.

10. Key Points

11. Practice Exercise

Create a small notification area with JavaScript.

Expected output: A new notification message appears inside the container.

Hint: Check that the container exists before appending the new element.

Solution:

const container = document.querySelector("#notifications");if (container) {  const notice = document.createElement("div");  notice.textContent = "You have a new message";  notice.classList.add("notice");  container.appendChild(notice);}

12. Final Summary

DOM basics start with two essential skills: selecting elements already on the page and creating new ones. querySelector gives you a flexible way to find the first matching element with CSS selectors, while createElement lets you build new nodes in memory before inserting them into the document.

Once you understand these two methods, you can handle most beginner DOM tasks: changing text, adding items, building components, and reacting to user actions. A good next step is to learn appendChild, append, classList, and addEventListener so you can connect selection, creation, and interaction into complete browser features.