June 24, 2026
innerHTML vs textContent: The Difference That Could Get Your Users Hacked
You have probably used both without thinking twice. You needed to put something on the page, you picked one, it worked, you moved on. Most…

By Ego
3 min read
You have probably used both without thinking twice. You needed to put something on the page, you picked one, it worked, you moved on. Most developers do.
But there is a real difference between these two. Not just syntax. Not just style. One of them can get your users hacked if you use it in the wrong place. And the scary part is the browser will not warn you. It will just quietly execute whatever you put in.
So let us actually talk about what these things are.
textContent: The Safe One
textContent sets or reads the plain text inside an element. Everything you pass to it gets treated as text. Nothing more.
element.textContent = "Hello Ego"
Simple. Works exactly as you expect. But here is the part worth knowing:
element.textContent = "Hello"
// displays literally on screen: Hello
// does not make text bold
You tried to pass HTML. textContent did not care. It displayed those tags as plain characters on the screen. No rendering. No parsing. Just text. That behaviour is exactly what makes it safe.
innerHTML: The Powerful One
innerHTML actually parses what you give it and renders it as HTML.
element.innerHTML = "Hello"
// renders: Hello in bold
That is useful when you genuinely need to insert HTML structure, not just text. But here is where things get serious. Imagine you build a comment section. A user types something and you display it using innerHTML:
const userComment = ""
commentBox.innerHTML = userComment
You just dropped a script tag directly into the DOM. The browser reads it, sees a script tag, and executes it. Now that attacker's code is running on your page with full access to everything JavaScript can touch, session data, cookies, login tokens.
And it gets worse. Script tags are not even the only way in.
commentBox.innerHTML = ""
The image source does not exist so it errors. The onerror attribute fires. JavaScript runs. No script tag needed.
commentBox.innerHTML = "Click here for prize"
Looks like a normal link. User clicks it. Code runs.
The danger has a name. XSS, Cross Site Scripting. And what makes it genuinely unsettling is that none of those examples above look dangerous at first glance. A comment. An image. A link. The browser does not question any of it. It just executes. If user content touches innerHTML, you have handed an attacker the keys to everything JavaScript can reach on your page.
So How Do You Display Safely?
If you are displaying plain text, a string, a number, a counter value, a hex colour, textContent is exactly right.
element.textContent = "Hello Ego"
element.textContent = count
element.textContent = hex
If you need to display actual HTML structure, bold text, a link, a list item, build the elements yourself in JavaScript:
const strong = document.createElement("strong")
strong.textContent = "Hello Ego"
element.appendChild(strong)
You create the element. You set its text safely with textContent. You append it. No user input ever touches innerHTML. No attack surface.
If the content is entirely your own code and you know exactly what is in it, innerHTML is fine:
element.innerHTML = "Hello Ego"
But the moment that content comes from a user, a form input, a URL parameter, anything typed by someone outside your own code, stay away from innerHTML. If you absolutely must use it with dynamic content, sanitise it first:
commentBox.innerHTML = DOMPurify.sanitize(userComment)
A Quick History Worth Knowing
innerHTML came first. Microsoft introduced it in Internet Explorer 4 in 1997. It was not part of any official standard. Microsoft just built it, other browsers copied it because developers used it everywhere, and it became a de facto feature of the web.
textContent came later, in 2004, as part of the official DOM Level 3 specification. It was introduced specifically because innerHTML was dangerous and developers needed a safe way to put plain text on the page without the security risk.
Microsoft shipped it without a standard, every browser copied it because developers were already using it everywhere, and the web just absorbed the decision. Seven years later the official spec introduced textContent specifically to give developers a way out. The older tool worked but created problems nobody anticipated. The safer one arrived to clean them up.
The pattern is familiar. var came before let and const. innerHTML came before textContent. The older tool worked but had problems. The safer one came to fix them.
There is no warning. No error. No red flag in the console. The browser will not stop you from making the wrong choice. That part is on you.