Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs

Dashboard
Notifications
Mark all as read
Q&A

What problem does innerHTML solves?

+1
−5

I understand that innerHTML does all the following actions:

  • It makes the element we work on (or even the entire DOM tree that we work on if that element is <body>) to be copy-pasted into a new empty document
  • The new document to which the data was copied, naturally lacks any JavaScript of the previous document
  • Although the data was copied into a new document, the browser will present the HTML change as if it was done in the original document

What problem would this property solve that can't be done with other methods, besides perhaps emptying the current document (why doing that?) and outputting the full HTML of an element (is it really the only way?)

About the MDN documentation:

  • Replacing the contents of an element: innerHTML does at least one extra thing as defuncting JavaScript so I would assume it's not a mere value replacement
  • Appending HTML to an element: I assume that this would typically be done with insertAdjacentHTML()?
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

3 comment threads

Can you provide an example of a change other than a replacement that supports your assumption? (5 comments)
`textContent` (like it's name implies) only does text (3 comments)
Documentation (2 comments)

1 answer

+7
−0

tl;dr

According to the documentation, innerHTML property "gets or sets the HTML or XML markup contained within the element". Basically, "that's all", but let's see it in more detail.


It makes the element we work on to be copy-pasted into a new empty document

No, the property itself doesn't copy anything (acessing element.innerHTML simply gets its value, but it doesn't make a copy of element). You can use its value and copy it to another element, though. And note that I said "element", not "document", because I can do this with any element in the DOM.

For example, let's suppose I have this HTML:

<div id="main">
  <p>lorem ipsum <span>dolor sit</span></p>
</div>
<div id="another"><p>some text</p></div>

And this JavaScript:

const main = document.querySelector('div#main');
const another = document.querySelector('div#another');

// copy main div's innerHTML to another div
another.innerHTML = main.innerHTML;

With this, the another div will have a copy of main div's contents: it'll have a p inside it (which in turn has a span). The old content (in this case, the paragraph with "some text") is replaced by the "lorem ipsum" paragraph (and also its children - in this case, the span "dolor sit" - as well). The result is both divs with the same contents.

Actually, when you set an element's innerHTML, the documentation says it does the following:

  1. The specified value is parsed as HTML or XML (based on the document type), resulting in a DocumentFragment object representing the new set of DOM nodes for the new elements.
  2. If the element whose contents are being replaced is a <template> element, then the <template> element's content attribute is replaced with the new DocumentFragment created in step 1.
  3. For all other elements, the element's contents are replaced with the nodes in the new DocumentFragment.

So, when I do element.innerHTML = someHTMLText, then someHTMLText is parsed and a DocumentFragment is created. This object is like a "lightweight document": it has nodes representing DOM elements, just like the document, but it contains only the nodes that were parsed. When the DocumentFragment is set to the element, it replaces whatever the element had before.

In the example above, when I do another.innerHTML = main.innerHTML, it first parses main.innerHTML (which is a string containing the HTML), resulting in a DocumentFragment, which is set to the another div (and any contents this div had before are replaced by the DocumentFragment). That's why the "some text" paragraph "disappears" and is replaced by the "lorem ipsum" one.

Therefore, using innerHTML is a way to copy contents from one element to another. But the property itself doesn't make copies. If I set element.innerHTML = someText and someText doesn't come from any existing element, it's not copying anything (just me being pedantic again).


Regarding "into a new empty document", I'm not sure what you mean. If you meant this:

document.body.innerHTML = someHTMLText;

Then you're not creating "a new empty document". You're just replacing the whole contents of the document's body by the new HTML text, which means the entire page will be replaced by that HTML. This doesn't create a new document, though.

Although the data was copied into a new document, the browser will present the HTML change as if it was done in the original document

As I said, it's not a new document. It's still the same, only its contents were changed.

The new document to which the data was copied, naturally lacks any whatsoever JavaScript of the previous document

Actually, the documentation says that script tags are also set to innerHTML, but they're not executed (although the same docs mention some ways to circumvent this).

emptying the current document (why doing that?)

I don't know, never needed to empty the current document.

But remind that innerHTML can be set to any element, not only the document.body. In this case, it's useful to make "dynamic things", such as elements changing according to some user actions (if I click somewhere, it updates some part of the page, etc).


outputting the full HTML of an element (is it really the only way?)

No, it's not the only way. But it's certainly the most straightforward one.

Other ways would be to do it manually, perhaps with this recursive function:

function getHtmlContent(el, str='') {
    if (el.nodeType === Node.TEXT_NODE) {
        str += el.textContent;
    } else {
        str += '<' + el.nodeName;
        if (el.attributes) {
            for (var i = 0; i < el.attributes.length; i++) {
                var attr = el.attributes[i];
                str += ' ' + attr.name + '="' + attr.value + '"';
            }
        }
        str += '>';
        for (var node of el.childNodes) {
            str = getHtmlContent(node, str);
        }
        str += '</' + el.nodeName + '>';
    }
    return str;
}

var html = getHtmlContent(someElement);

Which is tedious and error prone (I didn't test for very complex HTML structures, not sure how reliable it is).

Another option is to serialize the element, using a XMLSerializer:

var html = new XMLSerializer().serializeToString(el);

An important difference is that both solutions above include the elements tag, while innerHTML doesn't. Ex: if the element corresponds to <p><span>abc</span></p>, the paragraph's innerHTML is <span>abc</span>, while the solutions above also include the surrounding <p> tags. BTW, if you want the HTML to also include the own element's tag, just use outerHTML.


Replacing the contents of an element: innerHTML does some extra things so I would assume it's not a mere value replacement

Yes, it does extra things. As I previously said, setting element.innerHTML = someText makes someText to be fully parsed, creating a DocumentFragment, and replacing all the element's children by this new fragment. Which takes us to the next point:

Appending HTML to an element: I assume that this would typically be done with insertAdjacentHTML()?

I'd say insertAdjacentHTML is better than simply appending to innerHTML (although I still see a lot of code using the latter).

Appending to innerHTML like this:

element.innerHTML += someHTMLText;

Is considered bad because it forces a full parsing of the whole contents again. Remember that the code above is equivalent to:

element.innerHTML = element.innerHTML + someHTMLText;

Which means that I'm concatenating element.innerHTML and someHTMLText, and this creates a new string containing all the element's contents plus the new HTML text. Then this whole text will be parsed, resulting in a DocumentFragment, that will replace the element's contents.

insertAdjacentHTML would be a better solution to this case, because it parses only the new text being inserted. Hence, the code above could be changed to:

element.insertAdjacentHTML('beforeend', someHTMLText);

In this case, only someHTMLText is parsed, and inserted after the element's last child. This is better than parsing the whole element's contents (which is done when you append to innerHTML).


As a final note, setting innerHTML to the empty string is a way to remove all element's children. Also, directly setting innerHTML to some value is an option if you want to change the element's contents to something else entirely. But if you just want to change a small part of it (such as appending something in the end, or changing some specific child element), there are lots of other methods to do it (such as append, remove, replaceWith, etc).

Why does this post require moderator attention?
You might want to add some details to your flag.

2 comment threads

I as a non native English speaker, junior JavaScript programmer and as going through much stress, in ... (9 comments)
From your answer I could figure that `innerHTML` is a non-modular (does few different things that cou... (4 comments)

Sign up to answer this question »