XSS-safe rendering
Show user input safely with textContent and an escape function.
Why textContent?
innerHTML parses text as HTML, so a <script> tag or event attribute in the text leads to an XSS attack.
textContent inserts text as plain text; tags appear as characters and no script runs.
For extra safety we'll also write an escapeHtml function that converts &, <, > into HTML entities.
The escapeHtml function
The escapeHtml function converts three dangerous characters into HTML entities: the & sign and the less-than and greater-than characters. This way tags in user text appear as text on screen and don't run as scripts.
The function is written as an arrow function and returns a replace chain. Each replace call takes the previous result and applies the next change.
This layer together with textContent provides defense in depth: if one layer is bypassed, the other still protects.
Exercise Write safe rendering
Write an escapeHtml arrow function that converts &, <, > into HTML entities (with a replace chain). Then write a renderComment(text) function: create a paragraph with document.createElement("p"), set .textContent = text to insert it safely, and append it with commentsEl.appendChild(p).
Show example solution
const escapeHtml = (str) => str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
function renderComment(text) {
const p = document.createElement("p");
p.textContent = text;
commentsEl.appendChild(p);
}
Test yourself
-
Which is safe for user text?
el.____ = userInput;- element.innerHTML = text
- element.insertAdjacentHTML = text
- document.write(text)
- element.textContent = text
Show answer
element.textContent = text — Correct! textContent doesn't parse HTML, it's XSS-safe.
-
escapeHtml replace
const escapeHtml = (str) => str .replace(/</g, "____") .replace(/>/g, ">");Show answer
const escapeHtml = (str) => str .replace(/</g, "<") .replace(/>/g, ">"); -
Match characters to entities
- &
- &
- <
- <
- >
- >
- "
- "