70

I need to be able to add elements to a page given a raw text string of HTML, including any number of tags, attributes etc. Ideally I would like to be able to do something like with any arbitrary string of well-formed html;

 var theElement = document.createElement("<h1 id='title'>Some Title</h1><span style="display:inline-block; width=100px;">Some arbitrary text</span>");

document.getElementById("body").appendChild(theElement);

Obviously that doesn't work, I'm looking for good ways to achieve the same result. I'd like to avoid parsing the HTML if possible. I'm severely restricted on the tools I can use, no jQuery or outside includes and must be cross-browser and backward compatible down to IE6. Any help would be huge.

kirps
  • 1,345
  • 2
  • 17
  • 28

5 Answers5

87

Try assigning to the innerHTML property of an anonymous element and appending each of its children.

function appendHtml(el, str) {
  var div = document.createElement('div');
  div.innerHTML = str;
  while (div.children.length > 0) {
    el.appendChild(div.children[0]);
  }
}
var html = '<h1 id="title">Some Title</h1><span style="display:inline-block; width=100px;">Some arbitrary text</span>';
appendHtml(document.body, html); // "body" has two more children - h1 and span.
maerics
  • 151,642
  • 46
  • 269
  • 291
  • 2
    You should use a [DocumentFragment](http://ejohn.org/blog/dom-documentfragments/) instead of a div; it'll be faster and much easier to move the child nodes over. **Edit**: Scratch that comment, since you can't set `innerHTML` of a DocumentFragment. – Phrogz Apr 25 '12 at 05:20
  • the edit to switch to the while loop fixed the issue with the for loop using an index as appendChild actually removes the element from the div to append it to the body. Cloning the child node is a less elegant way to do this as well. – kirps Apr 25 '12 at 16:06
  • @kirps: yes, i finally tested that sample code and discovered the odd behavior of "appendChild" and its affect on the containing parent element's "children" attribute. – maerics Apr 25 '12 at 16:14
35

You can use insertAdjacentHTML:

document.body.insertAdjacentHTML("beforeend", theHTMLToInsert);

There are options other than beforeend, but it sounds like you want to append to the element, which is what beforeend does.

Live Example:

document.body.insertAdjacentHTML("beforeend", "<div>This is the new content.</div>");
<div>Existing content in <code>body</code>.</div>

Unlike using += with innerHTML, this doesn't require the browser to spin through the content of the element and create an HTML string to represent it, destroy those elements (including any event handlers they have on them), and replace them with the same elements plus your additions. It just adds your additions, leaving the existing content unchanged.

larsmoa
  • 12,604
  • 8
  • 62
  • 85
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    that was perfect...kudos – Rohan M Nabar Aug 07 '19 at 21:13
  • This answer is perfect. By using `innerHTML`, some webpages did work, like Google Calendar, Backlog, Amazon, etc. (I run in the console). By using `insertAdjacentHTML`, there is no effect to original web pages. Thank you so much! – Ngoc Nam Sep 07 '20 at 08:48
15
var el =  document.createElement("h1")
el.id="title";
el.innerHTML = "Some title";
document.body.appendChild(el);

var el2 =  document.createElement("span")
el2.style.display="block";
el2.style.width="100%";
el2.innerHTML = "Some arb text";
document.body.appendChild(el2);

Shoud work (fiddle: http://jsfiddle.net/gWHVy/)

edit: This is a solution for the special case that you know the properties of direct children of what you want to insert. Take a look at the solution of Aaron that works in the general case.

beardhatcode
  • 4,533
  • 1
  • 16
  • 29
  • 1
    This works, but doesn't answer the question of inserting arbitrary raw text HTML. – Richrd Jul 03 '18 at 15:05
  • Take a look at the solution of @Aaron . His approach will work just fine. However, this solution is more simple for the special case that you would want it in a span. – beardhatcode Jul 10 '18 at 15:38
8

You could get the elementId of the element under which you wish to insert the HTML and use innerHTML for adding the html.

document.getElementById("body").innerHTML = "<h1 id='title'>Some Title</h1><span>test</span>";
Vivek Viswanathan
  • 1,968
  • 18
  • 26
  • 2
    Not sure about `document.getElementById("body")` which in my opinion would be quite... NULL ! ;-). Use `document.getElementsByTagName('body')[0]` – Romain Bruckert Jun 19 '17 at 15:57
3

maerics solution fixed my problem straight away. I however needed to make a quick tweak to it to do what I needed. I have several scripts and stylesheets that load on click. I can't add either scripts or stylesheets as actual objects to the DOM post-load. If you set innerHTML for say, document.body, to contain the <link rel="stylesheet" /> part, it will only print the text and the browser will not recognize it as a link object. To fix this, I used the following code.

function appendHtml(el, str) {
  var div = document.createElement('div');
  div.innerHTML = str;
  while (div.children.length > 0) {
      if ( div.children[0].tagName == 'LINK' ) {
          // Create an actual link element to append later
          style = document.createElement('link');
          style.href = div.children[0].href;
          // append your other things like rel, type, etc
          el.appendChild(style);
      }
      el.appendChild(div.children[0]);
  }
}
apaderno
  • 28,547
  • 16
  • 75
  • 90
Aaron
  • 31
  • 1