31. Changing HTML Content
After selecting a DOM element, you can read and modify its content. JavaScript provides several ways to change HTML content, text, and element structure.
Code Example
Reading Content
const paragraph = document.querySelector("p");
// textContent — raw text, including text inside script/style
console.log(paragraph.textContent);
// innerText — visible text only (affected by CSS)
console.log(paragraph.innerText);
// innerHTML — the full HTML including tags
console.log(paragraph.innerHTML);
// Difference between textContent and innerText:
// textContent: fast, grabs all text (including display:none)
// innerText: slower, only visible text
Changing Content
const info = document.getElementById("info-student");
// textContent — safe from XSS, text only
info.textContent = "GPA: 3.75";
// innerHTML — you can insert HTML, but WATCH OUT FOR XSS!
info.innerHTML = "<strong>GPA: 3.75</strong> (Cum Laude)";
// Never do this with user input!
const userInput = '<script>alert("XSS")</script>';
// info.innerHTML = userInput; // DANGEROUS!
info.textContent = userInput; // Safe — displayed as plain text
insertAdjacentHTML
const container = document.getElementById("list");
// beforebegin — before the container (previous sibling)
container.insertAdjacentHTML("beforebegin", "<p>Before the container</p>");
// afterbegin — inside the container, before the first child
container.insertAdjacentHTML("afterbegin", "<li>New Item (Top)</li>");
// beforeend — inside the container, after the last child
container.insertAdjacentHTML("beforeend", "<li>New Item (Bottom)</li>");
// afterend — after the container (next sibling)
container.insertAdjacentHTML("afterend", "<p>Sesudah container</p>");
beforebegin ┌─────────────────────┐
│ container │
afterbegin │ ┌───────────────┐ │
│ │ first child │ │
│ └───────────────┘ │
│ ┌───────────────┐ │
│ │ last child │ │
beforeend │ └───────────────┘ │
└─────────────────────┘
afterend ┌─────────────────────┐
│ next element │
└─────────────────────┘
insertAdjacentElement
const container = document.getElementById("studentList");
// Create a new element
const item = document.createElement("div");
item.className = "student-item";
item.textContent = "Mike Johnson";
// Insert at a specific position
container.insertAdjacentElement("afterbegin", item);
// Keep a reference for further manipulation
const firstItem = container.querySelector(".student-item");
firstItem.style.backgroundColor = "#e8f5e9";
outerHTML
const card = document.querySelector(".card");
// Read outerHTML — the entire element including opening/closing tags
console.log(card.outerHTML);
// '<div class="card"><h3>Title</h3><p>Content</p></div>'
// Replace the entire element with new HTML
card.outerHTML = `
<div class="card highlight">
<h3>New Title</h3>
<p>New content</p>
</div>
`;
// the card reference is now INVALID because the element has been replaced
Creating New Elements
// createElement — create a new element
const card = document.createElement("div");
card.className = "card";
card.id = "card-1";
card.innerHTML = `
<h3>Card title</h3>
<p>Card content</p>
`;
// Add to the DOM with various methods
const container = document.getElementById("content");
// appendChild — add at the end
container.appendChild(card);
// prepend — add at the beginning
const header = document.createElement("h2");
header.textContent = "Student List";
container.prepend(header);
// insertBefore — add before a specific element
const ref = container.querySelector(".card");
const newCard = document.createElement("div");
newCard.className = "card";
newCard.textContent = "Card New";
container.insertBefore(newCard, ref);
// replaceChildren — replace all children
container.replaceChildren(
document.createElement("h2"),
document.createElement("p")
);
// remove — delete an element
card.remove();
// cloneNode — duplicate an element
const original = document.querySelector(".card");
const clone = original.cloneNode(true); // true = deep clone
container.appendChild(clone);
Example: Dynamic Table for Student Data
function createStudentTable(students) {
const container = document.getElementById("tableContainer");
// Create the table element
const table = document.createElement("table");
table.className = "table-student";
// Create thead
const thead = document.createElement("thead");
thead.innerHTML = `
<tr>
<th>No</th>
<th>StudentID</th>
<th>Name</th>
<th>Major</th>
<th>GPA</th>
<th>Classification</th>
<th>Action</th>
</tr>
`;
table.appendChild(thead);
// Create tbody
const tbody = document.createElement("tbody");
students.forEach((student, index) => {
const tr = document.createElement("tr");
// Calculate the classification
let classification = "Satisfactory";
if (student.gpa >= 3.5) classification = "Cum Laude";
else if (student.gpa >= 3.0) classification = "Excellent";
else if (student.gpa >= 2.5) classification = "Good";
// Color based on classification
let color = "#f44336";
if (student.gpa >= 3.5) color = "#4caf50";
else if (student.gpa >= 3.0) color = "#2196f3";
else if (student.gpa >= 2.5) color = "#ff9800";
tr.innerHTML = `
<td>${index + 1}</td>
<td>${student.studentId}</td>
<td>${student.name}</td>
<td>${student.major}</td>
<td>${student.gpa.toFixed(2)}</td>
<td style="color: ${color}; font-weight: bold">${classification}</td>
<td>
<button class="btn-detail" data-studentId="${student.studentId}">Details</button>
<button class="btn-delete" data-studentId="${student.studentId}">Delete</button>
</td>
`;
tbody.appendChild(tr);
});
table.appendChild(tbody);
// Add a summary row
const total = students.length;
const average = total > 0
? (students.reduce((sum, m) => sum + m.gpa, 0) / total).toFixed(2)
: "0.00";
const tfoot = document.createElement("tfoot");
tfoot.innerHTML = `
<tr>
<td colspan="4"><strong>Total: ${total} student</strong></td>
<td><strong>${average}</strong></td>
<td colspan="2"></td>
</tr>
`;
table.appendChild(tfoot);
// Render
container.innerHTML = "";
container.appendChild(table);
// Event delegation for the buttons
container.addEventListener("click", (event) => {
const btnDetail = event.target.closest(".btn-detail");
const btnDelete = event.target.closest(".btn-delete");
if (btnDetail) {
const studentId = btnDetail.dataset.studentId;
const student = students.find(m => m.studentId === studentId);
alert(`Details: ${student.name} - GPA ${student.gpa}`);
}
if (btnDelete) {
const studentId = btnDelete.dataset.studentId;
const index = students.findIndex(m => m.studentId === studentId);
if (index > -1) {
students.splice(index, 1);
createStudentTable(students); // re-render
}
}
});
}
// Data
const data = [
{ studentId: "2024001", name: "Mike Johnson", major: "CS", gpa: 3.75 },
{ studentId: "2024002", name: "Anna Reed", major: "IS", gpa: 3.20 },
{ studentId: "2024003", name: "John Smith", major: "CS", gpa: 2.85 },
{ studentId: "2024004", name: "Amy Lee", major: "SOC", gpa: 3.92 }
];
document.addEventListener("DOMContentLoaded", () => {
createStudentTable(data);
});
replaceChildren — Modern Replacement
const list = document.getElementById("courseList");
// Replace all content at once (more efficient than innerHTML)
list.replaceChildren(
createCourseItem("Algorithms", 3),
createCourseItem("Database", 3),
createCourseItem("Web Programming", 3)
);
function createCourseItem(name, credits) {
const li = document.createElement("li");
li.textContent = `${name} (${credits} credits)`;
return li;
}
Code Explanation
| Method | Explanation |
|---|---|
textContent |
Raw text — safe from XSS, fast |
innerHTML |
HTML markup — can be injected, use carefully |
innerText |
Visible text only (slow, affected by CSS) |
insertAdjacentHTML |
Insert HTML at 4 relative positions |
insertAdjacentElement |
Insert an element at 4 relative positions |
outerHTML |
Read/replace the entire element (including its own tags) |
createElement |
Create a new element (not yet in the DOM) |
appendChild |
Add a child at the end of the parent |
prepend |
Add a child at the beginning of the parent |
insertBefore |
Add a child before a reference node |
remove |
Remove an element from the DOM |
cloneNode(deep) |
Duplicate an element (true = deep clone) |
replaceChildren |
Replace all children at once |
Performance Tips
✅ Use documentFragment for batch inserts
❌ Avoid repeated innerHTML (causes re-render)
✅ Use textContent when only changing text
❌ Don't append elements one by one in a large loop
// Use a fragment for performance
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const li = document.createElement("li");
li.textContent = `Item ${i + 1}`;
fragment.appendChild(li);
}
document.getElementById("list").appendChild(fragment);
// Only 1 reflow, not 100!
Real-World Examples
A student dashboard that updates in real time:
class CampusDashboard {
constructor(container) {
this.container = document.querySelector(container);
this.data = [];
}
render() {
const fragment = document.createDocumentFragment();
// Header
const header = document.createElement("div");
header.className = "dashboard-header";
header.innerHTML = `
<h2>Dashboard Academic</h2>
<p>Update: ${new Date().toLocaleTimeString("en-US")}</p>
`;
fragment.appendChild(header);
// Stats cards
const stats = this.calculateStatistics();
const statsHTML = document.createElement("div");
statsHTML.className = "stats-grid";
statsHTML.innerHTML = `
<div class="stat-card">
<h3>${stats.total}</h3>
<p>Total Student</p>
</div>
<div class="stat-card">
<h3>${stats.averageGPA}</h3>
<p>Average GPA</p>
</div>
<div class="stat-card">
<h3>${stats.cumLaude}</h3>
<p>Cum Laude</p>
</div>
`;
fragment.appendChild(statsHTML);
// Table
const table = document.createElement("table");
table.className = "data-table";
table.innerHTML = `
<thead>
<tr>
<th>StudentID</th><th>Name</th><th>GPA</th><th>Status</th>
</tr>
</thead>
<tbody>
${this.data.map(student => `
<tr>
<td>${student.studentId}</td>
<td>${student.name}</td>
<td>${student.gpa.toFixed(2)}</td>
<td>${student.gpa >= 3.5 ? "🏆 Cum Laude" : "Active"}</td>
</tr>
`).join("")}
</tbody>
`;
fragment.appendChild(table);
// Render at once
this.container.replaceChildren(fragment);
}
calculateStatistics() {
const total = this.data.length;
const averageGPA = total > 0
? (this.data.reduce((sum, m) => sum + m.gpa, 0) / total).toFixed(2)
: "0.00";
const cumLaude = this.data.filter(m => m.gpa >= 3.5).length;
return { total, averageGPA, cumLaude };
}
updateData(newData) {
this.data = newData;
this.render();
}
}
// Usage
document.addEventListener("DOMContentLoaded", () => {
const dashboard = new CampusDashboard("#dashboard");
dashboard.updateData([
{ studentId: "2024001", name: "Mike", gpa: 3.75 },
{ studentId: "2024002", name: "Anna", gpa: 3.20 },
{ studentId: "2024003", name: "John", gpa: 2.85 },
{ studentId: "2024004", name: "Amy", gpa: 3.92 }
]);
});
Conclusion
- Use
textContentfor safe text, andinnerHTMLfor HTML (watch out for XSS). insertAdjacentHTMLlets you insert HTML at 4 relative positions without removing existing content.createElement+appendChildis the safest way to build elements.- Use
documentFragmentfor batch inserts to boost performance. replaceChildrenis the modern way to replace all children at once.