Creating a new DOM element from an HTML string using built-in DOM methods or Prototype

JavascriptDomPrototypejs

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

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:

Solution 2 - Javascript

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> element is used to declare fragments of HTML that can be utilized in scripts. The element is represented in the DOM as a HTMLTemplateElement which has a .content property of DocumentFragment type, to provide access to the template's contents. This means that you can convert an 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 April 2021, Can I use... estimates 96% 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.

Solution 3 - Javascript

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>

Solution 4 - Javascript

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

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

Solution 5 - Javascript

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;
}

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

Solution 6 - Javascript

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

Solution 7 - Javascript

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

Solution 8 - Javascript

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

Solution 9 - Javascript

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>

Solution 10 - Javascript

Why don't do with native js?

    var s="<span class='text-muted' style='font-size:.75em; position:absolute; bottom:3px; left:30px'>From <strong>Dan's Tools</strong></span>"
    var e=document.createElement('div')
    var r=document.createRange();
    r.selectNodeContents(e)
    var f=r.createContextualFragment(s);
    e.appendChild(f);
    e = e.firstElementChild;

Solution 11 - Javascript

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;
};

Usage:

document.createElementFromString("<h1>Hello World!</h1>");

Solution 12 - Javascript

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 literals
var a = 10, b = 5
var foo=`
<img 
  onclick="alert('The future starts today!')"   
  src='//placekitten.com/100/100'>
foo${a + b}
  <i>bar</i>
    <hr>`.toDOM();
document.body.appendChild(foo);

img {cursor: crosshair}

So, why not use directly .innerHTML += ? By doing so, the whole DOM is being recalculated by the browser, it's much slower.

https://caniuse.com/template-literals

Solution 13 - Javascript

Here's how to do it with PrototypeJS (as originally requested by the OP 12 years ago):

HTML:

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

JS:

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

Note that this is not jQuery!

Solution 14 - Javascript

Answer

  • Create a Template
  • Set the Template's innerHTML to your string .trim()
  • Create an Array of Template's children
  • Return children, child, or

function toElement(s='',c,t=document.createElement('template'),l='length'){
t.innerHTML=s.trim();c=[...t.content.childNodes];return c[l]>1?c:c[0]||'';}



console.log(toElement());
console.log(toElement(''));
console.log(toElement('    '));
console.log(toElement('<td>With td</td>'));
console.log(toElement('<tr><td>With t</td></tr>'));
console.log(toElement('<tr><td>foo</td></tr><tr><td>bar</td></tr>'));
console.log(toElement('<div><span>nested</span> <span>stuff</span></div>'));

Solution 15 - Javascript

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>

Solution 16 - Javascript

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>

Solution 17 - Javascript

You can use DOM parser:

const parser = new DOMParser();
const htmlString = "<strong>Beware of the leopard</strong>";
const doc3 = parser.parseFromString(htmlString, "text/html");

Reference

Solution 18 - Javascript

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');
    // ...
}

Solution 19 - Javascript

Fastest solution to render DOM from string:

let render = (relEl, tpl, parse = true) => {
  if (!relEl) return;
  const range = document.createRange();
  range.selectNode(relEl);
  const child = range.createContextualFragment(tpl);
  return parse ? relEl.appendChild(child) : {relEl, el};
};

And here u can check performance for DOM manipulation React vs native JS

Now u can simply use:

let element = render(document.body, `
<div style="font-size:120%;line-height:140%">
  <p class="bold">New DOM</p>
</div>
`);

And of course in near future u use references from memory cause var "element" is your new created DOM in your document.

And remember "innerHTML=" is very slow :/

Solution 20 - Javascript

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')"
}));

Solution 21 - Javascript

I've linked from this article.( Converting HTML string into DOM elements? )

For me, I want to find a way to convert a string into an HTML element. If you also have this need, you can try the following

const frag = document.createRange().createContextualFragment(
`<a href="/link.js">js</a> 
 <a>go</a>
`
) 
const aCollection = frag.querySelectorAll("a")
for (let [key, a] of Object.entries(aCollection)) {
  console.log(a.getAttribute("href"), a.textContent)
}

Solution 22 - Javascript

I have searched a lot for this myself and came across this solution which is neat.

const stringToHTML = (str) => {
	var parser = new DOMParser();
	var doc = parser.parseFromString(str, 'text/html');
	return doc.body;
};

String that I wanted to convert:

'<iframe src="https://player.vimeo.com/video/578680903?h=ea840f9223&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Total Body Balance"></iframe>'

The result:

<body><iframe src="https://player.vimeo.com/video/578680903?h=ea840f9223&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" title="Total Body Balance"></iframe></body>

Solution 23 - Javascript

Example with latest JS:

<template id="woof-sd-feature-box">
<div class="woof-sd-feature-box" data-key="__KEY__" data-title="__TITLE__" data-data="__OPTIONS__">
    <h4>__TITLE__</h4>
    <div class="woof-sd-form-item-anchor">
        <img src="img/move.png" alt="">
    </div>
</div>

</template>

<script>
create(example_object) {
        let html = document.getElementById('woof-sd-feature-box').innerHTML;
        html = html.replaceAll('__KEY__', example_object.dataset.key);
        html = html.replaceAll('__TITLE__', example_object.dataset.title);
        html = html.replaceAll('__OPTIONS__', example_object.dataset.data);
        //convertion HTML to DOM element and prepending it into another element
        const dom = (new DOMParser()).parseFromString(html, "text/html");
        this.container.prepend(dom.querySelector('.woof-sd-feature-box'));
    }
</script>

Solution 24 - Javascript

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

Solution 25 - Javascript

Visit https://www.codegrepper.com/code-examples/javascript/convert+a+string+to+html+element+in+js

const stringToHtml = function (str) {
	var parser = new DOMParser();
	var doc = parser.parseFromString(str, 'text/html');
	return doc.body;
}

Solution 26 - Javascript

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

Solution 27 - Javascript

Here is working code for me

I wanted to convert 'http://www.example.com">Text</a>'; string to HTML element

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

Solution 28 - Javascript

var msg = "

test
" jQuery.parseHTML(msg)

Solution 29 - Javascript

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

Use jnerator

Solution 30 - Javascript

This will work too:

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOmer BokhariView Question on Stackoverflow
Solution 1 - JavascriptCrescent FreshView Answer on Stackoverflow
Solution 2 - JavascriptMark AmeryView Answer on Stackoverflow
Solution 3 - JavascriptChristian d'HeureuseView Answer on Stackoverflow
Solution 4 - Javascriptmath2001View Answer on Stackoverflow
Solution 5 - JavascriptMunawwarView Answer on Stackoverflow
Solution 6 - JavascriptkojiroView Answer on Stackoverflow
Solution 7 - Javascriptwilliam maloView Answer on Stackoverflow
Solution 8 - JavascriptGibboKView Answer on Stackoverflow
Solution 9 - JavascriptusrboweView Answer on Stackoverflow
Solution 10 - JavascriptSam SaarianView Answer on Stackoverflow
Solution 11 - JavascriptRazaView Answer on Stackoverflow
Solution 12 - JavascriptNVRMView Answer on Stackoverflow
Solution 13 - JavascriptPablo BorowiczView Answer on Stackoverflow
Solution 14 - JavascriptMonwell ParteeView Answer on Stackoverflow
Solution 15 - Javascriptuser8629798View Answer on Stackoverflow
Solution 16 - JavascriptK-GunView Answer on Stackoverflow
Solution 17 - JavascriptMD SHAYONView Answer on Stackoverflow
Solution 18 - JavascriptWen QiView Answer on Stackoverflow
Solution 19 - JavascriptPaweł KołodziejczakView Answer on Stackoverflow
Solution 20 - JavascriptJxAxMxIxNView Answer on Stackoverflow
Solution 21 - JavascriptCarsonView Answer on Stackoverflow
Solution 22 - JavascriptFarhanView Answer on Stackoverflow
Solution 23 - Javascriptrealmag777View Answer on Stackoverflow
Solution 24 - JavascriptDenim DemonView Answer on Stackoverflow
Solution 25 - Javascriptosman akbacıView Answer on Stackoverflow
Solution 26 - JavascriptSaeed saeeydView Answer on Stackoverflow
Solution 27 - JavascriptSandeep BadaweView Answer on Stackoverflow
Solution 28 - Javascriptnitish kumarView Answer on Stackoverflow
Solution 29 - JavascriptBerezhView Answer on Stackoverflow
Solution 30 - JavascriptjackView Answer on Stackoverflow