
el.innerText
vs. el.textContent
The innerText
and textContent
properties of DOM elements sound similar, but they have distinct behaviors. This post explains the differences and when to use each.
Prelude
The main topic here is: How do I get the inner content of a DOM node?
Multiple ways one may know:
el.innerHTML
is what I remember to have learned firstel.innerText
I think I learned secondel.textContent
feels newest to me.
These are all the most common ways.
Let's dive into the difference of innerText
and textContent
, since these two get you the text in there, and they do already strip out the HTML, which is what is often needed when one wants to work with the actual content.
The Basics
Reading el.innerText
or el.textContent
returns the content of DOM node referred to by el
. For example, let's assume we have the following HTML:
<article id="my-article" style="color: blue;">the article's inner text</article>
<script>
const el = document.querySelector('#my-article');
document.write('innerText: ' + el.innerText + '<br>'); // write "the article's inner text" into the page
document.write('textContent: ' + el.textContent); // same as above
</script>
Proof: executing the above code results in:
The blue text is the actual <article>
(check it via right-mouse-click "Inspect" if you like). The document.write
s output is right below.
NOTE: document.write
is a "very old" function that is actually discouraged to use. It writes straight into the page in place, this is only possible because the <script>
tag is render-blocking.
We set the basics, now let's dive a bit deeper.
Embedded HTML
Using el
we can refer to any DOM node, which can also have children, cool thing is both remove the HTML and just return the text. While having the DOM nodes
a <b>c</b>
or a c
reading their content will return the same thing.
What if the tag <b>
has some style applied to it?
For example a <b style="display:none">c</b>
will still return a c
, but ONLY for el.textContent
.
innerText
returns the visible text only, which will be just a
!
See the following:
<article>
with <span style="display: none">an invisible span inside</span> or not?
</article>
It renders this:
Notice that textContent
also contains the invisible "an invisible span inside" string from inside the <span>
, while innerText
does not.
The Surrounding HTML
The visibility is also influenced by surrounding elements. It is quite obvious that an <article>
nested in an <main style="display: none">
is not shown and has no innerText. But there are more subtle behaviors that have an impact.
Embed the <article>
in a <details>
node, that the user can toggle open.
Let's try it:
<details>
<summary>Open/close me</summary>
<article>Inside of a details node</article>
</details>
This renders:
Open/close me
Ooops, do you see that the <details>
element is actually opened? That is because I added the code document.getElementById('3rd-details').open = true;
to open it after the innerText
and textContent
was written for the first time. The result afterward is different because the <article>
is visible now.
The HTML/CSS specifications say that the "computed value
of 'visibility' is 'visible'" then the content is returned in innerText
. Important to note is that "computed value" is not necessarily the "computed style", the CSS spec says. I was not able to find out a way to get the "computed value" via JavaScript. If sounds abstract? I agree. Anyway.
The browser is pretty smart about what "visible" means! Or not?
Overlayed Content
What about content that is overlayed by other content? For example a absolute positioned element, which is in the background and another one is just right on top of it.
Let's try it:
<article id="my-4th-article" style="position: absolute; left: 1em;">
Absolute positioned
</article>
<article style="background: white; opacity: 0.8; position: relative;">
O v e r l a y e d content
</article>
The overlay element has an explicit white background, a bit of opacity, just to prove that there is another one behind it.
It all renders like this:
So the browser is not that smart. The overlaying text is not returned even though that is the text we see in the place of the actual <article>
.
But to be honest, if that had worked the spec would probably be very much more complicated. Unnecessarily for such an edge case, I would say.
Overflowing Content
What about content that is cut off due to width limitations and hidden overflows? I expect it to work just as above, it is just way too edgy to detect that.
Let's see:
<span style="display: inline-flex; width: 4em; white-space: nowrap; overflow: hidden; background: lightyellow;">
Only 4em wide!
</span>
<span>Content after</span>
The first <span>
renders only with 4em width, the rest is cut off. The next <span>
starts right after it. That could mean the innerText
is also cut off, but I would be surprised.
As expected the innerText
contains the entire text even though it is visually cut off.
Off Screen Content
What about off-screen DOM elements? By this I mean an document.createElement
ed DOM node that is not rendered on the screen, it only exists in memory. So it is actually also not visible yet.
Let's create an element, give it some innerText
explicitly and then read the two properties of it.
<script>
const el = document.createElement('article');
el.innerText = 'I am off-screen ARTICLE';
</script>
The output is:
The MDN page also states this explicitly to work like that. Why? I guess that would need some digging into the HTML spec, feel free to do so find the links below.
Conclusion
This was a fun discovery, I learned a lot about the inner workings and also where to look for these two properties in the specification. They do not do magic, but it is useful to know the difference, especially in the case that it bites you. I experienced that, my initial motivation was triggered by a closed <details>
element. Now I know. I hope you were also able to take away something.
innerText
returns the visible text content of an element, taking into account CSS styles and layout but with limitations!
textContent
returns all the content, no matter if visible or not, HTML tags are stripped though. If you like to keep the HTML tags use innerHTML
.
If you want a less verbose, maybe easier to read description visit
MDN's innerText
and
MDN's textContent. If you like to dive deep read the
HTML specification on innerText
or
textContent
.