textContent is a DOM property used to read or update the text inside an element and all of its descendants. It is useful when you want the plain text content of a node without HTML rendering.
Use textContent when you need the raw text tree, innerText when you care about rendered text (layout-dependent), and innerHTML when you need markup. If you are selecting the node first, JavaScript querySelector is usually the next step before reading or updating the text.
Tested on: Node.js v20.18.2 for the small
console.logdemo. Fences that calldocumentuse{run=false}—paste into DevTools or run with jsdom / happy-dom and the matching markup.
Quick reference
| Goal | Property |
|---|---|
| Read/write plain text, all descendants | node.textContent |
| Text as rendered (CSS aware) | element.innerText |
| Parse or inject markup | element.innerHTML (XSS risk on assignment) |
Method 1: Read text-like data (Node-friendly demo)
In the browser, element.textContent returns one string with the text from the element and every descendant concatenated. This snippet only models a textContent field so you can run it in Node; real DOM nodes behave the same on the property read.
class DemoText {
constructor(text) {
this.textContent = text;
}
}
console.log("textcontent:", new DemoText("Hello DOM").textContent);You should see one line logging textcontent: Hello DOM.
Method 2: Update textContent in the browser
Load the HTML below in a page (or DevTools Elements + Console). The script selects #message and replaces its child text; the element keeps the same <p> wrapper.
<p id="message">Old text</p>
<script>
const message = document.querySelector("#message");
if (message) {
message.textContent = "New text";
}
</script>In the browser, the visible paragraph text should change from Old text to New text; there is no separate console.log in this fragment.
Assigning to textContent replaces the text inside the element without parsing HTML, so angle brackets show up as literal characters instead of new elements.
Method 3: Clear an element with textContent
With a real DOM, this removes all descendant text and elements under the selected node in one assignment.
document.querySelector("#output").textContent = "";After it runs against markup that includes #output, that subtree should be empty (no visible text). If #output is missing, this throws when the result of querySelector is null—guard with if (el) in production.
For removing the node itself, see JavaScript remove DOM element.
Method 4: Compare textContent, innerText, and innerHTML
Assume markup like <div class="box">Hi <b>there</b></div> (and CSS that could affect layout for innerText). Each property answers a different question about the same subtree.
const box = document.querySelector(".box");
console.log(box.textContent);
console.log(box.innerText);
console.log(box.innerHTML);You should see three lines: textContent includes hidden structure as plain text (here, "Hi there" with possible whitespace differences), innerText follows rendered text rules, and innerHTML returns the markup string including tags.
Choose the property that matches whether you need raw text, painted text, or source-like HTML.
Common questions about textContent in JavaScript
What does textContent return?
It returns the text content of a node and its descendants. If the reference is null (querySelector miss), reading or writing throws unless you guard first.
Is textContent faster than innerText?
textContent avoids layout work that innerText may trigger. Prefer it when you only need the text tree.
Does textContent remove HTML tags?
It does not parse HTML on read; it gives you the concatenated text. On write, it replaces children with a single text node.
What is the difference between textContent and innerHTML?
textContent reads or writes plain text. innerHTML reads or writes serialized HTML and must be treated as a XSS surface when the string includes untrusted data.
Summary
Use textContent in JavaScript to read, update, or clear the plain text inside DOM elements. It is the best default when you want raw text rather than rendered text or HTML markup, and it pairs naturally with querySelector and other selector APIs.

