By Omer Bokhari


2009-01-30 01:13:44 8 Comments

I have an HTML string representing an element: '<li>text</li>'. I'd like to append it to an element in the DOM (a ul in my case). How can I do this with Prototype or with DOM methods?

(I know i could do this easily in jQuery, but unfortunately we're not using jQuery.)

22 comments

@nitish kumar 2019-05-22 10:11:39

var msg = "test" jQuery.parseHTML(msg)

@Dwhitz 2019-05-22 10:31:31

Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made.

@xgqfrms-gildata 2018-05-28 11:45:50

HTML5 & ES6

<template>

Demo

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @description HTML5 Template
 * @augments
 * @example
 *
 */

/*

<template>
    <h2>Flower</h2>
    <img src="https://www.w3schools.com/tags/img_white_flower.jpg">
</template>


<template>
    <div class="myClass">I like: </div>
</template>

*/

const showContent = () => {
    // let temp = document.getElementsByTagName("template")[0],
    let temp = document.querySelector(`[data-tempalte="tempalte-img"]`),
        clone = temp.content.cloneNode(true);
    document.body.appendChild(clone);
};

const templateGenerator = (datas = [], debug = false) => {
    let result = ``;
    // let temp = document.getElementsByTagName("template")[1],
    let temp = document.querySelector(`[data-tempalte="tempalte-links"]`),
        item = temp.content.querySelector("div");
    for (let i = 0; i < datas.length; i++) {
        let a = document.importNode(item, true);
        a.textContent += datas[i];
        document.body.appendChild(a);
    }
    return result;
};

const arr = ["Audi", "BMW", "Ford", "Honda", "Jaguar", "Nissan"];

if (document.createElement("template").content) {
    console.log("YES! The browser supports the template element");
    templateGenerator(arr);
    setTimeout(() => {
        showContent();
    }, 0);
} else {
    console.error("No! The browser does not support the template element");
}
@charset "UTf-8";

/* test.css */

:root {
    --cololr: #000;
    --default-cololr: #fff;
    --new-cololr: #0f0;
}

[data-class="links"] {
    color: white;
    background-color: DodgerBlue;
    padding: 20px;
    text-align: center;
    margin: 10px;
}
<!DOCTYPE html>
<html lang="zh-Hans">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Template Test</title>
    <!--[if lt IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
    <![endif]-->
</head>

<body>
    <section>
        <h1>Template Test</h1>
    </section>
    <template data-tempalte="tempalte-img">
        <h3>Flower Image</h3>
        <img src="https://www.w3schools.com/tags/img_white_flower.jpg">
    </template>
    <template data-tempalte="tempalte-links">
        <h3>links</h3>
        <div data-class="links">I like: </div>
    </template>
    <!-- js -->
</body>

</html>

@Munawwar 2015-12-17 11:42:42

For certain html fragments like <td>test</td>, div.innerHTML, DOMParser.parseFromString and range.createContextualFragment (without the right context) solutions mentioned in other answers here, won't create the <td> element.

jQuery.parseHTML() handles them properly (I extracted jQuery 2's parseHTML function into an independent function that can be used in non-jquery codebases).

If you are only supporting Edge 13+, it is simpler to just use the HTML5 template tag:

function parseHTML(html) {
    var t = document.createElement('template');
    t.innerHTML = html;
    return t.content.cloneNode(true);
}

var documentFragment = parseHTML('<td>Test</td>');

@cyan 2016-01-28 08:06:51

This code works for many tds and trs too.

@Christian d'Heureuse 2017-10-28 22:03:45

Use insertAdjacentHTML(). It works with all current browsers, even with IE11.

var mylist = document.getElementById('mylist');
mylist.insertAdjacentHTML('beforeend', '<li>third</li>');
<ul id="mylist">
 <li>first</li>
 <li>second</li>
</ul>

@Jonas Äppelgran 2018-04-10 17:37:42

First, insertAdjacentHTML works with all browsers since IE 4.0.

@Jonas Äppelgran 2018-04-10 17:40:00

Second, it's great! A big plus compared to innerHTML += ... is that references to previous elements is still intact using this method.

@Jonas Äppelgran 2018-04-10 17:44:48

Third, possible values for the first argument is: beforebegin, afterbegin, beforeend, afterend. See the MDN article.

@Jordan 2018-11-07 11:56:53

best answer to me

@Mojimi 2019-07-01 13:21:50

Too bad it doesn't return the inserted HTML as an element

@NVRM 2018-06-17 20:34:37

To enhance furthermore the useful .toDOM() snippet that we can find in different places, we can now safely use backticks (template literals).

So we can have single and double quotes in the foo html declaration.

This behave like heredocs for those familiar with the term.

This can be enhanced furthermore with variables, to make complex templating:

Template literals are enclosed by the back-tick () (grave accent) character instead of double or single quotes. Template literals can contain placeholders. These are indicated by the dollar sign and curly braces (${expression}). The expressions in the placeholders and the text between them get passed to a function. The default function just concatenates the parts into a single string. If there is an expression preceding the template literal (tag here), this is called a "tagged template". In that case, the tag expression (usually a function) gets called with the processed template literal, which you can then manipulate before outputting. To escape a back-tick in a template literal, put a backslash \ before the back-tick.

String.prototype.toDOM=function(){
  var d=document,i
     ,a=d.createElement("div")
     ,b=d.createDocumentFragment()
  a.innerHTML = this
  while(i=a.firstChild)b.appendChild(i)
  return b
}

// Using template litterals
var a = 10, b = 5
var foo=`
<img 
  onclick="alert('The future start today!')"   
  src='//placekitten.com/100/100'>
foo${a + b}
  <i>bar</i>
    <hr>`.toDOM();
document.body.appendChild(foo);
img {cursor: crosshair}

https://caniuse.com/template-literals

@Crescent Fresh 2009-01-30 03:00:25

Note: most current browsers support HTML <template> elements, which provide a more reliable way of turning creating elements from strings. See Mark Amery's answer below for details.

For older browsers, and node/jsdom: (which doesn't yet support <template> elements at the time of writing), use the following method. It's the same thing the libraries use to do to get DOM elements from an HTML string (with some extra work for IE to work around bugs with its implementation of innerHTML):

function createElementFromHTML(htmlString) {
  var div = document.createElement('div');
  div.innerHTML = htmlString.trim();

  // Change this to div.childNodes to support multiple top-level nodes
  return div.firstChild; 
}

Note that unlike HTML templates this won't work for some elements that cannot legally be children of a <div>, such as <td>s.

If you're already using a library, I would recommend you stick to the library-approved method of creating elements from HTML strings:

@Shivanshu Goyal 2018-03-06 03:59:04

How to set innerHTML to the created div using jQuery without using this unsafe innerHTML assignment (div.innerHTML = "some value")

@Semmel 2018-04-03 18:22:39

The function name createElementFromHTML is misleading since div.firstChild returns a Node which is not a HTMLElement e.g. cannot node.setAttribute. To create an Element return div.firstElementChild from the function instead.

@Crescent Fresh 2018-04-03 19:18:57

@Semmel: haha uh oh here we go again....

@Ivan 2018-05-17 08:19:43

Thank you, the <div> wrapping the HTML I added with .innerHTML was annoying me. I never thought of using .firstChild.

@ed1nh0 2018-06-26 13:58:47

I'm trying to parse a SVG inside the created div and and the output is [object SVGSVGElement] while the console log gives me the correct DOM element. What am I doing wrong?

@ethan.roday 2018-06-27 22:33:07

Note, by the way, that this does not work for script tags. Script tags added to the DOM using innerHTML will not be executed. For those cases, better to go with var script = document.createElement('script'), and then use script.src or script.textContent depending on whether the script is inline. Then, add the script with document.body.appendChild(script).

@wedi 2018-08-09 09:05:19

Thank you, @Semmel!

@Христо Панайотов 2018-11-12 09:46:58

I would use firstElementChild instead of firstChild ( see w3schools.com/jsref/prop_element_firstelementchild.asp ) , because if there is space in front or end of template, the firstChild would return empty textNode

@Mark Amery 2016-02-13 21:25:59

HTML 5 introduced the <template> element which can be used for this purpose (as now described in the WhatWG spec and MDN docs).

A <template> is an HTML element which is allowed any other element type as a child. The template has a .content property that you can access with JavaScript which points to a DocumentFragment with the template's contents. This means that you can convert a HTML string to DOM elements by setting the innerHTML of a <template> element, then reaching into the template's .content property.

Examples:

/**
 * @param {String} HTML representing a single element
 * @return {Element}
 */
function htmlToElement(html) {
    var template = document.createElement('template');
    html = html.trim(); // Never return a text node of whitespace as the result
    template.innerHTML = html;
    return template.content.firstChild;
}

var td = htmlToElement('<td>foo</td>'),
    div = htmlToElement('<div><span>nested</span> <span>stuff</span></div>');

/**
 * @param {String} HTML representing any number of sibling elements
 * @return {NodeList} 
 */
function htmlToElements(html) {
    var template = document.createElement('template');
    template.innerHTML = html;
    return template.content.childNodes;
}

var rows = htmlToElements('<tr><td>foo</td></tr><tr><td>bar</td></tr>');

Note that similar approaches that use a different container element such as a div don't quite work. HTML has restrictions on what element types are allowed to exist inside which other element types; for instance, you can't put a td as a direct child of a div. This causes these elements to vanish if you try to set the innerHTML of a div to contain them. Since <template>s have no such restrictions on their content, this shortcoming doesn't apply when using a template.

However, template is not supported in some old browsers. As of January 2018, Can I use... estimates 90% of users globally are using a browser that supports templates. In particular, no version of Internet Explorer supports them; Microsoft did not implement template support until the release of Edge.

If you're lucky enough to be writing code that's only targeted at users on modern browsers, go ahead and use them right now. Otherwise, you may have to wait a while for users to catch up.

@Adi Prasetyo 2016-04-03 17:44:06

nice one, modern approach. Tested on Opera, let's forget IE

@shanef22 2016-05-26 21:23:39

This is an effective approach and very clean; however, (at least in Chrome 50) this breaks script tag handling. In other words, using this method to create a script tag and then appending it to the document (body or head) doesn't result in the tag being evaluated and hence prevents the script from being executed. (This may be by design if evaluation happens on attach; I couldn't say for sure.)

@Roger Gajraj 2016-06-13 06:27:50

LOVELY! you can even query for elements by doing something like: template.content.querySelector("img");

@Dai 2017-03-29 20:53:05

I don't see innerHTML defined as a property of DOM fragment objects (from <template>.content) on MDN: developer.mozilla.org/en-US/docs/Web/API/DocumentFragment

@Mark Amery 2017-09-21 10:55:12

@Dai indeed not, since there is no such property. You've misread my answer; I set the innerHTML of the template itself (which is an Element), not its .content (which is a DocumentFragment).

@Crescent Fresh 2018-01-10 20:02:15

My 9 year old answer is getting updates from the community as recently as today, and complaints that "it doesn't work". People, please stop. Just use this answer as the way forward. A 9 year old answer to anything browser related is simply irrelevant.

@BoltClock 2018-01-12 05:40:30

@Crescent Fresh: Do you want your answer deleted? I can do that.

@Crescent Fresh 2018-01-12 17:26:07

@BoltClock: does that help the community (honest question)? It's not incorrect, it reflects known information at the time. There are better answers (this one) but it doesn't mean mine doesn't have some historical significance at the very least.

@BoltClock 2018-01-12 17:29:10

@Crescent Fresh: Fair enough, I was of the impression you wanted your answer gone since you said it's now irrelevant, my apologies. A good compromise would be adding a statement to your answer pointing readers to this one, as has now been discussed on meta - let's just hope that the edit war doesn't pick back up from there.

@e-motiv 2018-04-24 15:50:31

There is one problem with it. If you have a tag in there with spaces inside(!) at start or end, they will be removed! Don't get me wrong, this is not about the spaces removed by html.trim but by inner parsing of innerHTML setting. In my case it removes important spaces being part of a textNode. :-(

@Sandeep Badawe 2018-01-08 10:23:19

Here is working code for me

I wanted to convert 'Text' string to HTML element

var diva = UWA.createElement('div');
diva.innerHTML = '<a href="http://wwww.example.com">Text</a>';
var aelement = diva.firstChild;

@Raza 2017-08-20 17:24:20

I added a Document prototype that creates an element from string:

Document.prototype.createElementFromString = function (str) {
    const element = new DOMParser().parseFromString(str, 'text/html');
    const child = element.documentElement.querySelector('body').firstChild;
    return child;
};

@Mark Amery 2017-12-21 17:59:56

Note that - as pointed out elsewhere on this page - this won't work for tds.

@Saeed saeeyd 2017-07-11 06:05:22

You can use the following function to convert the text "HTML" to the element

function htmlToElement(html)
{
  var element = document.createElement('div');
  element.innerHTML = html;
  return(element);
}
var html="<li>text and html</li>";
var e=htmlToElement(html);

@Mark Amery 2017-12-21 18:00:56

-1; this is the same technique as proposed in the accepted answer and has the same drawbacks - notably, not working for tds.

@kojiro 2011-09-06 21:53:15

Newer DOM implementations have range.createContextualFragment, which does what you want in a framework-independent way.

It's widely supported. To be sure though, check its compatibility down in the same MDN link, as it will be changing. As of May 2017 this is it:

Feature         Chrome   Edge   Firefox(Gecko)  Internet Explorer   Opera   Safari
Basic support   (Yes)    (Yes)  (Yes)           11                  15.0    9.1.2

@Mark Amery 2016-02-13 15:31:32

Note that this has similar drawbacks to setting the innerHTML of a div; certain elements, like tds, will be ignored and not appear in the resulting fragment.

@akauppi 2016-08-05 12:33:50

"There are reports that desktop Safari did at one point support Range.createContextualFragment(), but it is not supported at least in Safari 9.0 and 9.1." (MDN link in the answer)

@GibboK 2017-02-28 14:31:14

You can create valid DOM nodes from a string using:

document.createRange().createContextualFragment()

The following example adds a button element in the page taking the markup from a string:

let html = '<button type="button">Click Me!</button>';
let fragmentFromString = function (strHTML) {
  return document.createRange().createContextualFragment(strHTML);
}
let fragment = fragmentFromString(html);
document.body.appendChild(fragment);

@Mark Amery 2017-12-21 17:54:10

Even though this creates a DocumentFragment object, it still - to my great surprise - suffers from the same defect as the accepted answer: if you do document.createRange().createContextualFragment('<td>bla</td‌​>'), you get a fragment that just contains the text 'bla' without the <td> element. Or at least, that's what I observe in Chrome 63; I haven't delved into the spec to figure out whether it's the correct behavior or not.

@math2001 2017-02-24 21:48:41

No need for any tweak, you got a native API:

const toNodes = html =>
    new DOMParser().parseFromString(html, 'text/html').body.childNodes

@Mark Amery 2017-12-21 17:46:33

This suffers from the same major drawback as the accepted answer - it will mangle HTML like <td>text</td>. This is because DOMParser is trying to parse a full HTML document, and not all elements are valid as root elements of a document.

@Mark Amery 2017-12-21 17:59:25

-1 because this is a duplicate of an earlier answer that explicitly pointed out the drawback mentioned in my comment above.

@usrbowe 2016-06-08 12:39:02

I am using this method (Works in IE9+), although it will not parse <td> or some other invalid direct childs of body:

function stringToEl(string) {
    var parser = new DOMParser(),
        content = 'text/html',
        DOM = parser.parseFromString(string, content);

    // return element
    return DOM.body.childNodes[0];
}

stringToEl('<li>text</li>'); //OUTPUT: <li>text</li>

@Denim Demon 2016-02-08 10:59:21

function domify (str) {
  var el = document.createElement('div');
  el.innerHTML = str;

  var frag = document.createDocumentFragment();
  return frag.appendChild(el.removeChild(el.firstChild));
}

var str = "<div class='foo'>foo</div>";
domify(str);

@Pablo Borowicz 2009-02-19 15:13:51

With Prototype, you can also do:

HTML:

<ul id="mylist"></ul>

JS:

$('mylist').insert('<li>text</li>');

@JxAxMxIxN 2013-09-21 03:47:51

For the heck of it I thought I'd share this over complicated but yet simple approach I came up with... Maybe someone will find something useful.

/*Creates a new element - By Jamin Szczesny*/
function _new(args){
    ele = document.createElement(args.node);
    delete args.node;
    for(x in args){ 
        if(typeof ele[x]==='string'){
            ele[x] = args[x];
        }else{
            ele.setAttribute(x, args[x]);
        }
    }
    return ele;
}

/*You would 'simply' use it like this*/

$('body')[0].appendChild(_new({
    node:'div',
    id:'my-div',
    style:'position:absolute; left:100px; top:100px;'+
          'width:100px; height:100px; border:2px solid red;'+
          'cursor:pointer; background-color:HoneyDew',
    innerHTML:'My newly created div element!',
    value:'for example only',
    onclick:"alert('yay')"
}));

@william malo 2013-05-03 00:02:50

Heres a simple way to do it:

String.prototype.toDOM=function(){
  var d=document
     ,i
     ,a=d.createElement("div")
     ,b=d.createDocumentFragment();
  a.innerHTML=this;
  while(i=a.firstChild)b.appendChild(i);
  return b;
};

var foo="<img src='//placekitten.com/100/100'>foo<i>bar</i>".toDOM();
document.body.appendChild(foo);

@Koen. 2016-03-23 11:32:51

@MarkAmery the difference here is that he uses a fragment to allow multiple root element be appended in the DOM, which is an added benefit. If only William did mention that is his answer...

@Corey Alix 2017-02-15 07:11:45

Does not work with "<tr/>".

@K-Gun 2012-12-13 12:39:13

Late but just as a note;

It's possible to add a trivial element to target element as a container and remove it after using.

// Tested on chrome 23.0, firefox 18.0, ie 7-8-9 and opera 12.11.

<div id="div"></div>

<script>
window.onload = function() {
    var foo, targetElement = document.getElementById('div')
    foo = document.createElement('foo')
    foo.innerHTML = '<a href="#" target="_self">Text of A 1.</a> '+
                    '<a href="#" onclick="return !!alert(this.innerHTML)">Text of <b>A 2</b>.</a> '+
                    '<hr size="1" />'
    // Append 'foo' element to target element
    targetElement.appendChild(foo)

    // Add event
    foo.firstChild.onclick = function() { return !!alert(this.target) }

    while (foo.firstChild) {
        // Also removes child nodes from 'foo'
        targetElement.insertBefore(foo.firstChild, foo)
    }
    // Remove 'foo' element from target element
    targetElement.removeChild(foo)
}
</script>

@Berezh 2012-09-25 00:39:23

var jtag = $j.li({ child:'text' }); // Represents: <li>text</li>
var htmlContent = $('mylist').html();
$('mylist').html(htmlContent + jtag.html());

Use jnerator

@jack 2012-04-11 22:02:29

This will work too:

$('<li>').text('hello').appendTo('#mylist');

It feels more like a jquery way with the chained function calls.

@Tim Ferrell 2015-04-16 03:48:36

Does it feel like jQuery because it is jQuery?

@kumar_harsh 2015-07-07 13:35:43

That last line is just hilarious!

@Wen Qi 2011-05-21 07:40:44

Here's my code, and it works:

function parseTableHtml(s) { // s is string
    var div = document.createElement('table');
    div.innerHTML = s;

    var tr = div.getElementsByTagName('tr');
    // ...
}

@Mark Amery 2016-02-13 15:37:14

Fails if the element to be created is itself a table.

Related Questions

Sponsored Content

47 Answered Questions

[SOLVED] Convert form data to JavaScript object with jQuery

74 Answered Questions

[SOLVED] How can I convert a string to boolean in JavaScript?

  • 2008-11-05 00:13:08
  • Kevin
  • 1674977 View
  • 2209 Score
  • 74 Answer
  • Tags:   javascript

14 Answered Questions

[SOLVED] How can I select an element by name with jQuery?

34 Answered Questions

27 Answered Questions

[SOLVED] Remove all child elements of a DOM node in JavaScript

  • 2010-10-17 20:51:00
  • Polaris878
  • 700688 View
  • 730 Score
  • 27 Answer
  • Tags:   javascript dom

41 Answered Questions

[SOLVED] Sort array of objects by string property value

13 Answered Questions

33 Answered Questions

[SOLVED] $(document).ready equivalent without jQuery

  • 2009-04-28 21:51:11
  • FlySwat
  • 943122 View
  • 1851 Score
  • 33 Answer
  • Tags:   javascript jquery

31 Answered Questions

[SOLVED] How to manage a redirect request after a jQuery Ajax call

31 Answered Questions

[SOLVED] endsWith in JavaScript

Sponsored Content