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.
- querySelector finds the first matching element in the document or inside another element.
- createElement builds a brand-new element node in memory.
- These methods are usually combined: find a container, create content, and insert it into the container.
- The DOM is dynamic, so changes made with JavaScript appear in the page immediately.
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
- Updating status messages after a form submits.
- Creating task items, cards, tags, or table rows from user input.
- Building dropdown menus or navigation items dynamically.
- Showing search results from an API response.
- Adding or removing CSS classes based on user actions.
- Reading values from the page, such as titles, counters, or input fields.
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
- querySelector uses CSS selector rules, so invalid selectors can throw a syntax error.
- createElement creates only HTML elements in the current document; it does not clone existing nodes.
- Elements created with createElement are disconnected until appended or inserted.
- If your script runs before the HTML exists, querySelector may return null.
- Some elements, like form controls, may need extra properties such as value or checked instead of only textContent.
- Repeatedly appending inside a loop can be slower than building a fragment first for large updates.
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
- querySelector finds the first element that matches a CSS selector.
- createElement builds a new element, but it is not visible until you insert it.
- Always handle the possibility that querySelector returns null.
- Use textContent, classes, and attributes to configure nodes before adding them.
- querySelectorAll is the better choice when you need multiple matches.
11. Practice Exercise
Create a small notification area with JavaScript.
- Use querySelector to find a container element with the id notifications.
- Use createElement to make a new div.
- Set the message text to "You have a new message".
- Add a class named notice.
- Append the new element to the container.
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.