196

How to append a HTML string such as

var str = '<p>Just some <span>text</span> here</p>';

to the <div> with the id test?

(Btw div.innerHTML += str; is not acceptable.)

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385

11 Answers11

386

Use insertAdjacentHTML which is supported in all current browsers:

div.insertAdjacentHTML( 'beforeend', str );

The position parameter beforeend will add inside the element, after its last child.

Live demo: http://jsfiddle.net/euQ5n/

Neil
  • 54,642
  • 8
  • 60
  • 72
  • 1
    @alex It's the same concept: parsing a HTML string and putting it into the DOM. But the functionality is different - `innerHTML` puts the string into the element (replacing all children), whereas `insertAdjacentHTML` puts it (1) before the element, (2) after the element, (3) inside the element before the first child, or (4) inside the element after the last child. – Šime Vidas Sep 06 '11 at 23:14
  • 5
    @alex `insertAdjacentHTML` is faster than appending to `innerHTML`, because `insertAdjacentHTML` doesn't serialize and reparse the existing children of the element. – hsivonen Oct 21 '11 at 17:31
  • 3
    Also, `insertAdjacentHTML` maintains the values of altered form elements, whereas appending to `innerHTML` rebuilds the element and loses all form context. – Brandon Gano Apr 02 '13 at 17:20
  • Cool but I'd suggest 'beforebegin' instead of 'beforeend' – Ivan Silkin Oct 05 '22 at 22:12
  • 1
    not to be confused with `insertAdjacent`**`Element`**`(..)`, which requires an actual `Element` as its second parameter, not a string: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement – Abdull Apr 21 '23 at 06:54
47

Performance

AppendChild (E) is more than 2x faster than other solutions on chrome and safari, insertAdjacentHTML(F) is fastest on firefox. The innerHTML= (B) (do not confuse with += (A)) is second fast solution on all browsers and it is much more handy than E and F.

Details

Set up environment (2019.07.10) MacOs High Sierra 10.13.4 on Chrome 75.0.3770 (64-bit), Safari 11.1.0 (13604.5.6), Firefox 67.0.0 (64-bit)

enter image description here

  • on Chrome E (140k operations per second) is fastest, B (47k) and F (46k) are second, A (332) is slowest
  • on firefox F (94k) is fastest, then B(80k), D (73k), E(64k), C (21k) slowest is A(466)
  • on Safari E(207k) is fastest, then B(89k), F(88k), D(83k), C (25k), slowest is A(509)

You can replay test in your machine here

function A() {    
  container.innerHTML += '<p>A: Just some <span>text</span> here</p>';
}

function B() {    
  container.innerHTML = '<p>B: Just some <span>text</span> here</p>';
}

function C() {    
  $('#container').append('<p>C: Just some <span>text</span> here</p>');
}

function D() {
  var p = document.createElement("p");
  p.innerHTML = 'D: Just some <span>text</span> here';
  container.appendChild(p);
}

function E() {    
  var p = document.createElement("p");
  var s = document.createElement("span"); 
  s.appendChild( document.createTextNode("text ") );
  p.appendChild( document.createTextNode("E: Just some ") );
  p.appendChild( s );
  p.appendChild( document.createTextNode(" here") );
  container.appendChild(p);
}

function F() {    
  container.insertAdjacentHTML('beforeend', '<p>F: Just some <span>text</span> here</p>');
}

A();
B();
C();
D();
E();
F();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

This snippet only for show code used in test (in jsperf.com) - it not perform test itself. 
<div id="container"></div>
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
33

Is this acceptable?

var child = document.createElement('div');
child.innerHTML = str;
child = child.firstChild;
document.getElementById('test').appendChild(child);

jsFiddle.

But, Neil's answer is a better solution.

alex
  • 479,566
  • 201
  • 878
  • 984
  • 1
    @Šime Working with the DOM API *always* feels like a hack :P Would you prefer to unserialise the string *without* `innerHTML`? – alex Sep 06 '11 at 22:55
  • Well yes, if there is another way to utilize the browser's HTML parser, I would love to know... – Šime Vidas Sep 06 '11 at 22:58
  • 1
    @Šime - I think there's only two ways to utilize the browser's HTML parser, innerHTML and document.write. And if you think innerHTML is a hack ... – Alohci Sep 06 '11 at 23:02
  • @Alohci There *is* another way: `insertAdjacentHTML`. – Šime Vidas Sep 06 '11 at 23:10
  • @Šime - So I see. I must admit I didn't know about that. I've up voted Neil's answer. I'm trying to find the spec for it. The link from developer.mozilla.org doesn't lead to it any more. – Alohci Sep 06 '11 at 23:20
  • @Alohci It's in the HTML5 standard under ["3.5 Dynamic markup insertion"](http://www.w3.org/TR/html5/apis-in-html-documents.html#dom-insertadjacenthtml). Interestingly, for some reason it has been ditched from the HTML Living Standard (which is a more relevant document when it comes to HTML). – Šime Vidas Sep 06 '11 at 23:30
  • 1
    @Šime -Thanks. I found the WHATWG version. It's in the [DOM Parsing and Serialization](http://html5.org/specs/dom-parsing.html#insertadjacenthtml()) spec. It indicates that as well as innerHTML and insertAdjacentHTML, there's outerHTML and, I think, createContextualFragment. – Alohci Sep 06 '11 at 23:35
  • @Alohci A new spec? Neat `^_^` – Šime Vidas Sep 06 '11 at 23:42
  • @Alohci, @Šime: `createContextualFragment()` is a method of DOM Range and does use the browser's HTML parser. – Tim Down Sep 07 '11 at 00:24
  • @ChristopherJamesCalo: Yeah, but the example the OP gave did. – alex Oct 24 '11 at 06:13
11

The idea is to use innerHTML on an intermediary element and then move all of its child nodes to where you really want them via appendChild.

var target = document.getElementById('test');
var str = '<p>Just some <span>text</span> here</p>';

var temp = document.createElement('div');
temp.innerHTML = str;
while (temp.firstChild) {
  target.appendChild(temp.firstChild);
}

This avoids wiping out any event handlers on div#test but still allows you to append a string of HTML.

Chris Calo
  • 7,518
  • 7
  • 48
  • 64
4

The right way is using insertAdjacentHTML. In Firefox earlier than 8, you can fall back to using Range.createContextualFragment if your str contains no script tags.

If your str contains script tags, you need to remove script elements from the fragment returned by createContextualFragment before inserting the fragment. Otherwise, the scripts will run. (insertAdjacentHTML marks scripts unexecutable.)

hsivonen
  • 7,908
  • 1
  • 30
  • 35
  • Thank you for mentioning `createContextualFragment `. I was searching for a way to make some html includes with scripts run only if the user agrees to set a cookie. – schliflo May 09 '18 at 15:40
2

Quick Hack:


<script>
document.children[0].innerHTML="<h1>QUICK_HACK</h1>";
</script>

Use Cases:

1: Save as .html file and run in chrome or firefox or edge. (IE wont work)

2: Use in http://js.do

In Action: http://js.do/HeavyMetalCookies/quick_hack

Broken down with comments:

<script>

//: The message "QUICK_HACK" 
//: wrapped in a header #1 tag.
var text = "<h1>QUICK_HACK</h1>";

//: It's a quick hack, so I don't
//: care where it goes on the document,
//: just as long as I can see it.
//: Since I am doing this quick hack in
//: an empty file or scratchpad, 
//: it should be visible.
var child = document.children[0];

//: Set the html content of your child
//: to the message you want to see on screen.
child.innerHTML = text;

</script>

Reason Why I posted:

JS.do has two must haves:

  1. No autocomplete
  2. Vertical monitor friendly

But doesn't show console.log messages. Came here looking for a quick solution. I just want to see the results of a few lines of scratchpad code, the other solutions are too much work.

KANJICODER
  • 3,611
  • 30
  • 17
1

This can solve

 document.getElementById("list-input-email").insertAdjacentHTML('beforeend', '<div class=""><input type="text" name="" value="" class="" /></div>');
Rafael Senne
  • 59
  • 1
  • 5
  • 3
    Welcome to Stack overflow. Please explain your code as part of an answer to provide some context rather than just pasting a long single line of code. Although you understand it others may not understand what its doing. – TResponse Feb 07 '18 at 00:57
1

InnerHTML clear all data like event for existing nodes

append child with firstChild adds only first child to innerHTML. For example if we have to append:

 <p>text1</p><p>text2</p>

only text1 will show up

What about this:

adds special tag to innerHTML by append child and then edit outerHTML by deleting tag we've created. Don't know how smart it is but it works for me or you might change outerHTML to innerHTML so it doesn't have to use function replace

function append(element, str)
{

  var child = document.createElement('someshittyuniquetag');
  
  child.innerHTML = str;

  element.appendChild(child);

  child.outerHTML = child.outerHTML.replace(/<\/?someshittyuniquetag>/, '');

// or Even child.outerHTML = child.innerHTML


  
}
<div id="testit">
This text is inside the div
<button onclick="append(document.getElementById('testit'), '<button>dadasasdas</button>')">To div</button>
<button onclick="append(this, 'some text')">to this</button>
</div>
0

Why is that not acceptable?

document.getElementById('test').innerHTML += str

would be the textbook way of doing it.

Nick Brunt
  • 9,533
  • 10
  • 54
  • 83
  • 9
    It would [kill event handlers](http://jsfiddle.net/v6qbc/) attached to `#test` though. That is generally not desirable. – alex Sep 06 '11 at 22:57
  • Interesting that it does that. Doesn't seem logical really. – Nick Brunt Sep 06 '11 at 23:04
  • 3
    It's logical I guess if you think about the serialising of the HTML to a string and then setting the HTML back. – alex Sep 06 '11 at 23:05
  • I guess the JavaScript would have to be run again to reset the event handler. Fair enough. – Nick Brunt Sep 06 '11 at 23:08
  • 1
    @Nick You don't want to stringify (serialize) a part of the DOM just so that you can concatenate it with another string and then parse the whole thing back into the DOM. As alex said, the serialization won't record bound event handlers (among other things). Even if he serialization could capture everything, you still wouldn't want to do it. – Šime Vidas Sep 06 '11 at 23:23
0

The answer to my Question was just this; a simple Map with an empty value; and all I can get is a very heavy answer and not precise. I wonder who closed my question... didn't even bother to read

"use strict"
try{
  const fruits = new Map([["Banana",""],["Apples", ""], ["Orange"," "]]);

let text = "<h1>Fruits</h1>" + "<ul>";

fruits.forEach(function(value, key){
  text += "<li>" + key + value + "<br>" + "</li>" });

text +="</li> ";

document.getElementById('demo').innerHTML = text;
}
catch(err){
 document.getElementById('theError').innerHTML = err;
}
Troy Cura
  • 1
  • 2
-1

Shortest - 18 chars (not confuse += (mention by OP) with = more details here)

test.innerHTML=str

var str = '<p>Just some <span>text</span> here</p>';

test.innerHTML=str
<div id="test"></div>
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345