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
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

81%
+7 −0
Q&A What problem does innerHTML solves?

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...

posted 2y ago by hkotsubo‭  ·  edited 2y ago by hkotsubo‭

Answer
#3: Post edited by user avatar hkotsubo‭ · 2021-10-01T18:43:48Z (over 2 years ago)
  • # tl;dr
  • According to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML), `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:
  • ```html
  • <div id="main">
  • <p>lorem ipsum <span>dolor sit</span></p>
  • </div>
  • <div id="another"><p>some text</p></div>
  • ```
  • And this JavaScript:
  • ```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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#operational_details) 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`](https://developer.mozilla.org/en-US/docs/Web/API/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`, I'm creating a `DocumentFragment` (the result of parsing `main` div's `innerHTML`) and setting it 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:
  • ```javascript
  • 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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations) 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 `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 straighforward one**.
  • Other ways would be to do it manually:
  • ```javascript
  • 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);
  • ```
  • Or serialize the element, using a [`XMLSerializer`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer):
  • ```javascript
  • 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 surroundings `<p>` tags. BTW, if you want the HTML to also include the own element's tag, just use [`outerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML).
  • ---
  • > *Replacing the contents of an element: `innerHTML` does some extra things so I would assume it's not a mere value replacement*
  • Yes, 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:
  • ```javascript
  • 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:
  • ```javascript
  • element.innerHTML = element.innerHTML + someHTMLText;
  • ```
  • Which means I'm getting the current `element`'s contents and appending some stuff to it. This creates a whole new string containing all the element's contents plus the new HTML text, which will then be parsed, resulting in a `DocumentFragment`, that will replace the `element`'s contents.
  • [`insertAdjacentHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/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:
  • ```javascript
  • 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 its 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](https://developer.mozilla.org/en-US/docs/Web/API/Element#methods) to do it (such as `append`, `remove`, `replaceWith`, etc).
  • # tl;dr
  • According to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML), `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:
  • ```html
  • <div id="main">
  • <p>lorem ipsum <span>dolor sit</span></p>
  • </div>
  • <div id="another"><p>some text</p></div>
  • ```
  • And this JavaScript:
  • ```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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#operational_details) 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`](https://developer.mozilla.org/en-US/docs/Web/API/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:
  • ```javascript
  • 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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations) 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:
  • ```javascript
  • 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`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer):
  • ```javascript
  • 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`](https://developer.mozilla.org/en-US/docs/Web/API/Element/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:
  • ```javascript
  • 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:
  • ```javascript
  • 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`](https://developer.mozilla.org/en-US/docs/Web/API/Element/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:
  • ```javascript
  • 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](https://developer.mozilla.org/en-US/docs/Web/API/Element#methods) to do it (such as `append`, `remove`, `replaceWith`, etc).
#2: Post edited by user avatar hkotsubo‭ · 2021-10-01T16:28:57Z (over 2 years ago)
  • # tl;dr
  • According to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML), `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:
  • ```html
  • <div id="main">
  • <p>lorem ipsum <span>dolor sit</span></p>
  • </div>
  • <div id="another"><p>some text</p></div>
  • ```
  • And this JavaScript:
  • ```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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#operational_details) 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`](https://developer.mozilla.org/en-US/docs/Web/API/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`, I'm creating a `DocumentFragment` (the result of parsing `main` div's `innerHTML`) and setting it 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:
  • ```javascript
  • 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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations) 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 `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 straighforward one**.
  • Other ways would be to do it manually:
  • ```javascript
  • 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);
  • ```
  • Or serialize the element, using a [`XMLSerializer`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer):
  • ```javascript
  • 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 surroundings `<p>` tags. BTW, if you want the HTML to also include the own element's tag, just use [`outerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML).
  • ---
  • > *Replacing the contents of an element: `innerHTML` does some extra things so I would assume it's not a mere value replacement*
  • Yes, 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:
  • ```javascript
  • 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:
  • ```javascript
  • element.innerHTML = element.innerHTML + someHTMLText;
  • ```
  • Which means I'm getting the current `element`'s contents and appending some stuff to it. This creates a whole new string, which will then be parsed, resulting in a `DocumentFragment`, that will replace the `element`'s contents.
  • [`insertAdjacentHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/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:
  • ```javascript
  • 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 its 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](https://developer.mozilla.org/en-US/docs/Web/API/Element#methods) to do it (such as `append`, `remove`, `replaceWith`, etc).
  • # tl;dr
  • According to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML), `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:
  • ```html
  • <div id="main">
  • <p>lorem ipsum <span>dolor sit</span></p>
  • </div>
  • <div id="another"><p>some text</p></div>
  • ```
  • And this JavaScript:
  • ```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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#operational_details) 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`](https://developer.mozilla.org/en-US/docs/Web/API/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`, I'm creating a `DocumentFragment` (the result of parsing `main` div's `innerHTML`) and setting it 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:
  • ```javascript
  • 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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations) 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 `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 straighforward one**.
  • Other ways would be to do it manually:
  • ```javascript
  • 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);
  • ```
  • Or serialize the element, using a [`XMLSerializer`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer):
  • ```javascript
  • 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 surroundings `<p>` tags. BTW, if you want the HTML to also include the own element's tag, just use [`outerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML).
  • ---
  • > *Replacing the contents of an element: `innerHTML` does some extra things so I would assume it's not a mere value replacement*
  • Yes, 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:
  • ```javascript
  • 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:
  • ```javascript
  • element.innerHTML = element.innerHTML + someHTMLText;
  • ```
  • Which means I'm getting the current `element`'s contents and appending some stuff to it. This creates a whole new string containing all the element's contents plus the new HTML text, which will then be parsed, resulting in a `DocumentFragment`, that will replace the `element`'s contents.
  • [`insertAdjacentHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/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:
  • ```javascript
  • 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 its 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](https://developer.mozilla.org/en-US/docs/Web/API/Element#methods) to do it (such as `append`, `remove`, `replaceWith`, etc).
#1: Initial revision by user avatar hkotsubo‭ · 2021-10-01T13:22:36Z (over 2 years ago)
# tl;dr

According to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML), `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:

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

And this JavaScript:

```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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#operational_details) 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`](https://developer.mozilla.org/en-US/docs/Web/API/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`, I'm creating a `DocumentFragment` (the result of parsing `main` div's `innerHTML`) and setting it 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:

```javascript
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](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations) 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 `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 straighforward one**.

Other ways would be to do it manually:

```javascript
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);
```

Or serialize the element, using a [`XMLSerializer`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer):

```javascript
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 surroundings `<p>` tags. BTW, if you want the HTML to also include the own element's tag, just use [`outerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML).

---

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

Yes, 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:

```javascript
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:

```javascript
element.innerHTML = element.innerHTML + someHTMLText;
```

Which means I'm getting the current `element`'s contents and appending some stuff to it. This creates a whole new string, which will then be parsed, resulting in a `DocumentFragment`, that will replace the `element`'s contents.

[`insertAdjacentHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/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:

```javascript
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 its 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](https://developer.mozilla.org/en-US/docs/Web/API/Element#methods) to do it (such as `append`, `remove`, `replaceWith`, etc).