Skip to content

Text Content in the DOM — Complete Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Text Content in the DOM. We cover key concepts, practical examples, and best practices to help you master this topic.

textContent vs innerText vs nodeValue control how JavaScript reads and writes text in the DOM, with important differences in performance and whitespace handling.

What You'll Learn

  • The difference between textContent, innerText, and nodeValue
  • How whitespace handling differs between each property
  • Performance characteristics and when to use each
  • How text nodes work in the context of the DOM tree

Why It Matters

Using the wrong text property leads to unexpected results — extra whitespace, missing text from hidden elements, or poor performance. Choosing the right one makes your code predictable and efficient.

Real-World Use

  • A search feature uses textContent to index page text (includes hidden content)
  • A "read more" feature uses innerText to count visible characters
  • A syntax highlighter manipulates text nodes directly to preserve formatting
flowchart LR
  A[Text Access] --> B[textContent]
  A --> C[innerText]
  A --> D[nodeValue]
  B --> E[All text, all elements]
  B --> F[Includes hidden content]
  B --> G[Fastest, no layout]
  C --> H[Visible text only]
  C --> I[Triggers reflow]
  C --> J[Respects CSS display]
  D --> K[Single text node]
  D --> L[Requires node reference]

Understanding textContent

The textContent property returns the text content of all child nodes, including script and style elements, without any formatting. It does not trigger layout and is the fastest text access method.

const container = document.querySelector('.article');

// Read all text content
const allText = container.textContent;
console.log('Text content length:', allText.length);

// textContent includes text from hidden elements
// It also includes text from script and style tags
const hiddenText = document.querySelector('.hidden').textContent;
console.log('Hidden element text:', hiddenText);

// Setting textContent replaces all children with a single text node
container.textContent = 'This replaces everything inside the container';
console.log('New content:', container.textContent);
console.log('Child count:', container.children.length);

Expected output: The textContent includes all text regardless of visibility. After setting, the container has zero child elements and only a single text node.

Understanding innerText

The innerText property approximates the rendered text content as a user would see it. It respects CSS visibility, layout, and whitespace collapsing.

const element = document.querySelector('.description');

// Read visible text
const visibleText = element.innerText;
console.log('Visible text:', visibleText);

// innerText differs from textContent:
// 1. It does not include hidden elements
// 2. It collapses whitespace
// 3. It includes line breaks as they appear visually
// 4. It triggers a reflow (slower)

// Example with hidden content
const mixedContainer = document.querySelector('.mixed');
console.log('textContent includes hidden:', mixedContainer.textContent.includes('hidden'));
console.log('innerText excludes hidden:', mixedContainer.innerText.includes('hidden'));

Expected output: The innerText shows only visible text. textContent includes the hidden text while innerText does not. innerText also reflects line breaks and spacing as rendered.

Working with nodeValue

The nodeValue property works on text nodes directly, not on elements. It reads or writes the actual text data of a node.

// Get the first text node of an element
const paragraph = document.querySelector('p');
const textNode = paragraph.firstChild;

// Check if it is a text node
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
    console.log('Text node value:', textNode.nodeValue);
    console.log('Text node length:', textNode.length);

    // Modify the text node directly
    textNode.nodeValue = 'Modified text content';
}

// nodeValue on an element returns null
console.log('Element nodeValue:', paragraph.nodeValue);

Expected output: The text node value is logged and then modified. The nodeValue of the element itself is null because elements do not have a text value.

Whitespace Handling

Browsers normalize whitespace differently depending on the CSS display property and the API used.

// HTML:
// <div class="whitespace-demo">
//     Hello     World
//     <span>Nested</span>
//     Goodbye
// </div>

const demo = document.querySelector('.whitespace-demo');

// textContent preserves all whitespace
console.log('textContent:', JSON.stringify(demo.textContent));

// innerText normalizes whitespace
console.log('innerText:', JSON.stringify(demo.innerText));

// textContent shows the actual whitespace from the HTML source
// innerText shows what the user visually sees

Expected output: textContent includes all whitespace (newlines, multiple spaces, indentation). innerText normalizes runs of whitespace to single spaces and includes line breaks where block elements are.

Performance Considerations

textContent is significantly faster than innerText because it does not trigger layout calculations.

// Performance comparison
const largeContainer = document.getElementById('large-content');

console.time('textContent');
const tc = largeContainer.textContent;
console.timeEnd('textContent');

console.time('innerText');
const it = largeContainer.innerText;
console.timeEnd('innerText');

// innerText is typically 2-10x slower than textContent
// because it must compute styles and layout
// to determine what text is visible

// Best practice: use textContent unless you specifically
// need the visual rendering of innerText

Expected output: The time measurements show innerText taking longer than textContent. For large documents, the difference can be milliseconds to tens of milliseconds.

Common Mistakes

  1. Using innerText when you should use textContent — innerText triggers reflow unnecessarily if you just need the raw text. Use textContent for reading and comparing text.
  2. Confusing nodeValue with textContent — nodeValue only works on text nodes and returns null for elements. textContent works on any node and returns combined text of all descendants.
  3. Expecting textContent to reflect visual formatting — textContent does not collapse whitespace or add line breaks. The output may look different from what the user sees.
  4. Setting innerText to a string with HTML — innerText, like textContent, sets plain text. HTML tags are not parsed and appear as literal text.
  5. Assuming textContent and innerText return the same length — They often differ because textContent preserves whitespace and includes hidden content while innerText does not.

Practice Questions

  1. What is the main performance difference between textContent and innerText? textContent does not trigger layout (reflow). innerText must compute styles to determine visible text, making it slower.
  2. Does innerText include text from elements with display:none? No. innerText only returns text from visible elements. textContent includes everything.
  3. How do you access the text of a specific text node? Get a reference to the text node and use its .nodeValue property.
  4. Challenge: Write a function that returns the text content of an element with normalized whitespace (single spaces, trimmed), using textContent for performance but producing output similar to innerText.

FAQ

What does 'triggers reflow' mean?

It means the browser must recalculate layout positions and styles before returning the result. This is computationally expensive, especially on large pages.

Can I use innerText on input elements?

No. For input elements, use the value property to read or set the text.

Does textContent include the content of script tags?

Yes. textContent includes all text descendants, including <script> and <style> tags. innerText excludes them.

What happens to the old child nodes when I set textContent?

They are all removed and replaced by a single text node. Any event listeners on the old children are lost.

Is there a way to set text without destroying child elements?

No. Setting textContent or innerText replaces all children. Use a text node and appendChild to add text without removing elements.

Mini Project

Create a search feature that filters a list of items as the user types. Each list item contains visible text and a hidden data field (using a span with display:none). Use textContent for the search to include the hidden data. Display the results count. Compare using textContent vs innerText for the search and observe the difference in results.

What's Next

Continue with Lesson 11: Document Fragment to learn how document fragments enable efficient batch DOM updates without triggering multiple reflows.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro