The Subtle Differences Between .innerText, .textContent, and .innerHTML in JavaScript

A “.inner” Look

Travis Prol
4 min readJul 28, 2020

At first glance, .innerHTML, .textContent, and .innerText look very similar when manipulating DOM elements in JavaScript. While it looks like you may be completing your task, you could be leaving your site open to vulnerabilities without even knowing.

.innerText and .textContent

These two elements appear to do the same exact thing on the surface, but act slightly differently in the DOM. The .innerText property represents the rendered text in an HTML element, while the .textContent property represents all of the text in the element.

For the purposes of this blog, I have slightly modified a lab from Mod3 in Flatiron School’s Software Engineering program called “Toy Tale”.

index.html in Google Chrome

Inside of each character character card, there is the toy’s name, photo, the number of likes, and a like button. Here is what my code looked like for each card:

index.js

When we look at line 29 of my code, we see a paragraph with an ID of ‘paragraph’, a span with the amount of likes in the JSON database, and the word ‘Likes.’

We can use the Google Chrome console to take a look at the .innerText and .textContent of this paragraph. As expected, both return the same thing, “13 Likes.”

Google Chrome Console

This is because the rendered (.innerText) text is “13 Likes,” and all of the text inside (.textContent) is also “13 Likes.” If any of this content were not visible, however, we would get different results.

After modifying my CSS to hide all of the spans on the page, my card now only shows the word “Likes,” but not the actual number of likes.

index.css and Woody Card

When I go to my Google Chrome console and look at these properties again, we get an interesting behavior:

Google Chrome Console

We now see that the .innerText of the paragraph is “Likes,” and the .textContent is “13 Likes.” This is due to the fact that .innerText reads the rendered text, and .textContent reads all of the text.

.innerHTML

.innerHTML does exactly what you think it does. It shows you the HTML of the element you call it on.

Google Chrome Console

Similarly to .textContent, .innerHTML will show you everything in the element that you call it on. The way this code is set up, however, we have a big vulnerability in the code.

Index.js and the Create a New Toy Form

When we look at this code, we can see that whatever name we put in the form will go to line 27 in our code and will appear as an H2, and the image url will go to line 28. Since we have this set up to change the .innerHTML, whatever we type in that form, including HTML, will render to the page. What would happen in we pasted the code for that form in the name field, and submitted the form?

New Toy Card and JSON Database

We can see that a new toy card was added with a form, and the form actually persisted to my JSON database as a new toy. This form might not do anything right now, but if the right code is put into the form, there is an opportunity for users to manipulate data in a way that you did not intend them to. The solution is to refactor our code so that our card is not populated with HTML, but instead is populated with appends.

Index.js

You might notice that I still used .innerHTML on the p tag above. This is okay because that element cannot be affected by whatever is submitted in the form. When we attempt to do the same thing now and paste the code from the form, we get a much different result.

index.html in Google Chrome

You can see that the card is not a form, but just the text we put into the form. The vulnerability is now gone! While our site does have a random card with HTML code on it, there is no way for a user to change the functionality of the site via our form.

--

--

Travis Prol

Full Stack Web Developer 🧑🏻‍💻 Artists Who Code 🤓 Lets go Yanks ⚾️