The error "innerHTML is not a function" trips up JavaScript learners and experienced developers alike. The root cause is simple: innerHTML is a property, not a method. Adding parentheses and calling it like a function triggers a TypeError. The fix is straightforward—assign to innerHTML instead of invoking it.
The Error in Context
Suppose a div exists in your HTML:
“`html
<div id="row">Data 1</div>
“`
Accessing it incorrectly looks like this:
“`javascript
Const element = document.getElementById("row").innerHTML("Hello");
“`
This throws `TypeError: innerHTML is not a function` because `getElementById` returns an HTMLElement, and innerHTML on that element is a property. Parentheses try to invoke it as a callable function.
The corrected approach assigns the new content:
“`javascript
Const element = document.getElementById("row");
Element.innerHTML = "Hello";
“`
The div now displays "Hello." The same pattern applies everywhere: reading innerHTML returns current HTML, assigning to it replaces the contents.
Why This Mistake Is So Common
Developers familiar with jQuery-style syntax expect something like `$(element).html("Hello")`—a method that accepts arguments. Modern vanilla JavaScript handles this differently. Properties receive assignments; methods receive calls. InnerHTML sits firmly on the property side of that divide.
This confusion extends beyond innerHTML. TextContent, value, src, and similar DOM properties all get miscalled as functions. Internalising the pattern—properties assign, methods call—eliminates an entire class of errors.
The Security Trade-Off
InnerHTML parses its input as HTML, which creates risk when handling untrusted content. A string like `<img src=x onerror=alert(1)>` will execute rather than display as text. Setting innerHTML from URL parameters, form fields, or API responses opens a direct cross-site scripting (XSS) vulnerability.
Three safer paths exist. TextContent sets plain text without HTML parsing—use it whenever markup is unnecessary. SetHTML, a newer Element method, sanitises input and strips unsafe markup automatically. Dedicated sanitiser libraries offer granular control but introduce a dependency.
Our Analysis: When innerHTML Fits
InnerHTML is not inherently dangerous. It belongs in your toolkit when you control the input entirely and need formatted markup. Replacing one block of your own HTML with another, with no user input in the chain, is exactly the use case innerHTML was built for.
The risk is that "trusted" becomes "untrusted" silently. Code accepting only your own content gains a feature pulling in user-generated content. The safe default: reach for textContent first, and upgrade to innerHTML or setHTML only when formatting is genuinely needed—and when you consciously accept the sanitisation responsibility.
The property-versus-method distinction carries a broader lesson. Once it clicks, the category of "X is not a function" errors shrinks permanently.
Worked Example: Rendering User Comments
You fetch comments from an API and inject them into a container:
“`javascript
Const p = document.createElement("p");
P.textContent = comment.text;
Container.appendChild(p);
“`
Using textContent inserts the text literally. Any `<script>` tags in the comment render as harmless text rather than executing. If formatting is necessary, switch to setHTML with its built-in sanitiser, which strips scripts and event handlers while preserving safe markup.
| Method | Use When | Parses HTML | Auto-Sanitisation |
|---|---|---|---|
| innerHTML | You control the content and need HTML formatting | Yes | No |
| textContent | Inserting plain text (including user input) | No | Yes (by design) |
| setHTML | User input requires formatted output | Yes | Yes (built-in) |
Key takeaways
- InnerHTML is a property: assign to it, never call it.
- Use textContent for any user-supplied or untrusted text.
- Use setHTML or a sanitiser when user input needs formatting.
- Start with the safest option; upgrade only when necessary.
Frequently asked questions
Why does "innerHTML is not a function" occur?
You are calling innerHTML with parentheses. It is a property, so assign to it rather than invoking it.
Is innerHTML safe with user input?
Generally no. Unless you sanitise the input first, textContent is the safer choice for plain text.
What separates innerHTML from textContent?
InnerHTML parses input as HTML. TextContent inserts everything as literal text, including potentially dangerous markup.
Does a built-in HTML sanitiser exist?
Yes. The setHTML method on Element sanitises input automatically and removes unsafe markup by default.