Course: JavaScript Beginner
Lesson 14: Changing Text, Classes, and Styles in the DOM
Level
Beginner
Estimated Reading Time
10–15 minutes
Goal
By the end of this lesson, the learner will be able to:
- Change an element's text content and inner HTML using
textContentandinnerHTML - Add, remove, and toggle CSS classes using the
classListAPI - Apply inline styles through
element.styleand understand when not to
Frontend Development Context
Selecting an element is only the first step. The real power of DOM manipulation is what you do next: update a message when the user submits a form, show an error label in red, add an "active" class to a nav link, toggle a sidebar open and closed, or replace placeholder text with real data from an API. These are the interactions users experience every time they use a web app.
The classList API is particularly important because it bridges the gap between JavaScript behavior and CSS styling. Instead of writing inline styles in JavaScript (which are hard to override and maintain), you use JavaScript to add or remove class names, and let your CSS stylesheet define what those classes look like. This separation of concerns is a fundamental pattern in professional frontend development.
Explanation
Changing text content: element.textContent sets or gets the text inside an element, ignoring any HTML tags. It is safe to use with user-provided data because it does not parse the content as HTML. element.innerHTML sets or gets the content including HTML markup — useful for inserting formatted content, but dangerous with untrusted input because it can execute malicious scripts.
The classList API: element.classList is an object with methods for managing CSS classes. .add("class-name") adds a class. .remove("class-name") removes it. .toggle("class-name") adds the class if it is absent, or removes it if it is present — perfect for on/off states like open menus and active filters. .contains("class-name") returns true if the class is currently applied.
Inline styles: element.style.propertyName sets an inline CSS style. CSS property names with hyphens are written in camelCase: background-color becomes element.style.backgroundColor. Inline styles have the highest CSS specificity, which makes them hard to override later. Use them sparingly — only for styles that must be computed dynamically (like animation positions or user-specified colors). Prefer classList for everything that can be expressed as a predefined CSS class.
Code Example
This example implements a notification banner that can be shown, styled, and dismissed:
const banner = document.querySelector("#notification-banner");
const bannerText = document.querySelector("#banner-message");
const closeBtn = document.querySelector("#close-banner");
function showNotification(message, type) {
// Update text safely
bannerText.textContent = message;
// Set the type class (success, error, warning)
banner.classList.remove("success", "error", "warning");
banner.classList.add(type);
banner.classList.remove("hidden");
}
closeBtn.addEventListener("click", function () {
banner.classList.add("hidden");
});
// Show a success notification
showNotification("Profile updated successfully!", "success");
Code Explanation
bannerText.textContent = message safely sets the text of the banner. Using textContent ensures that even if message contains characters like < or >, they are displayed as literal text and not interpreted as HTML — which protects against cross-site scripting.
The showNotification function first removes all existing type classes (success, error, warning) to ensure only one is applied at a time. Then .add(type) applies the correct class. This pattern — remove all, then add one — is cleaner than trying to track which class was previously applied.
.classList.remove("hidden") reveals the banner by removing a CSS class that presumably sets display: none. This is the correct approach: the CSS file defines what "hidden" means visually, and JavaScript simply applies or removes that class. If the design changes later (perhaps hidden elements fade out instead of disappearing instantly), you only update the CSS — the JavaScript stays the same.
The close button's click handler adds the "hidden" class back, which hides the banner again. This toggle between "has hidden class" and "does not have hidden class" is one of the most common patterns in frontend JavaScript.
Pattern Highlights
✅ Positive Pattern: Use
classList.add(),.remove(), and.toggle()to control appearance — define what those classes mean in your CSS stylesheet, and let JavaScript only manage which classes are applied.
⚠️ Neutral Note:
element.innerHTML = contentis convenient for inserting HTML, but never use it with unsanitized user input. Content that contains<script>tags or event handler attributes can execute arbitrary JavaScript.
❌ Negative Pattern: Setting many inline styles directly (
el.style.color,el.style.padding,el.style.fontSize) scatters presentation logic into JavaScript and creates styles that are hard to override. Use CSS classes instead.
Common Mistakes
Mistake 1: Using innerHTML with user input
Setting innerHTML from untrusted content is a cross-site scripting (XSS) vulnerability. The browser parses and executes any HTML — including <script> tags and inline event handlers — found in the string.
const userInput = `<img src=x onerror="alert('hacked')">`;
element.innerHTML = userInput; // executes the onerror script!
// Safe alternative:
element.textContent = userInput; // displays it as plain text
Always use textContent for user-provided content. Only use innerHTML with strings you control entirely.
Mistake 2: Replacing all classes by setting className instead of using classList
Setting element.className = "new-class" replaces all existing classes, not just the one you want to change.
const card = document.querySelector(".product-card");
// Card already has classes: "product-card featured"
card.className = "highlighted"; // now only "highlighted" — lost the others!
// Correct:
card.classList.add("highlighted"); // adds without removing existing classes
Use classList.add() to add without destroying, and classList.remove() to remove a specific class.
Mistake 3: Trying to toggle a class and then immediately checking if the animation finished
classList.toggle() is synchronous — it changes the class instantly. But CSS transitions or animations triggered by that class change take time. Reading a style property right after toggling does not reflect the animated state.
menu.classList.toggle("open");
console.log(menu.offsetHeight); // reads the layout before animation completes
If you need to respond after a CSS transition ends, listen for the transitionend event on the element rather than reading layout values immediately after toggling.
Quick Recap
textContentsets plain text safely;innerHTMLsets HTML content but must never be used with untrusted user inputclassList.add(),.remove(),.toggle(), and.contains()manage CSS classes without affecting others- Prefer
classListover inlineelement.stylefor appearance changes — keep CSS in stylesheets, not in JavaScript - Toggling a class on/off (using
.toggle()) is the standard pattern for show/hide, open/close, and active/inactive states