Converting HTML string into DOM elements?
Asked Answered
P

9

313

Is there a way to convert HTML like:

<div>
<a href="#"></a>
<span></span>
</div>

or any other HTML string into DOM element? (So that I could use appendChild()). I know that I can do .innerHTML and .innerText, but that is not what I want -- I literally want to be capable of converting a dynamic HTML string into a DOM element so that I could pass it in a .appendChild().

Update: There seems to be confusion. I have the HTML contents in a string, as a value of a variable in JavaScript. There is no HTML content in the document.

Portcullis answered 23/6, 2010 at 17:23 Comment(2)
Check this out: #494643Shumway
If you want something closer HTML instead of node, I suggeste to use the following function ;) ` var stringToHTML = function (str) { var dom = document.createElement('div'); dom.innerHTML = str; return dom; }; `Kiker
W
513

You can use a DOMParser, like so:

var xmlString = "<div id='foo'><a href='#'>Link</a><span></span></div>";
var doc = new DOMParser().parseFromString(xmlString, "text/xml");
console.log(doc.firstChild.innerHTML); // => <a href="#">Link...
console.log(doc.firstChild.firstChild.innerHTML); // => Link
Wein answered 23/6, 2010 at 17:58 Comment(18)
That looks cleaner than my own solution. Let me see.Portcullis
Thanks, it works great. After reading Mozilla article I realized that the browsers can also parse XML AJAX responses -- so browsers like IE that do not support DOMParser, I use synchronous AJAX calls with data URIs to parse the XML. :)Portcullis
This is just what I was looking for! Works great for custom printing in a Windows 8 applications.Diplodocus
There can be issues with this approach when IE goes into 'compatibility mode' as it is IE8+.Selflove
If you get errors because you're trying to load HTML instead of XML like the <br> tag than look here: developer.mozilla.org/en-US/docs/DOM/DOMParser under "DOMParser HTML extension for other browsers" to support loading HTMLCf
For anyone who is having trouble with inline styles not rendering, check out my Q&A: Why is DOMParser not preserving inline styles of parsed DOM?Telethon
@Wein Why can't you just say text/html for HTML parsing?Plainclothesman
@Djack You can, but then you get 'html' and 'body' tags automatically generated.Paddle
Note: I found it vital to use "text/html" instead of "text/xml", if placing the created nodes back to browser's DOM (Safari 9.1.2). Otherwise, the CSS rendering didn't work correctly. If you use this, use '.body' to bypass the auto-inserted body element.Paddle
as of time of writing: this isn't supported on Opera Mini (3% of internet traffic)Giralda
I'm not able to get the rendered value. it showing me [object HTMLHtmlElement]Makebelieve
this worked for me adding an array of string "<meta >" tags to head dynamically. thanks.Ec
This was very useful. I was attempting how to decode a document where the innerHTML was essentially another DOM fragment.Serin
I'm trying to use this in jest, instead of getting document I'm getting DocumentImplRandall
@Wein This solution will not work, if you want to add special meaning to your element. For example <a href="www.google.com">test</a> should redirect to www.google.com but it will not. To keep element context you have to change type to text/html. I have this problem and I was really confused why this solution is not working.Turro
@ShaikhArbaaz may be you are converting it to string when you use element.innerHTMl=dom; use element.appendChild(dom); developer.mozilla.org/en-US/docs/Web/API/Node/appendChildPolyhydroxy
I get with td.appendChild(domparsed): Uncaught (in promise) DOMException: Failed to execute 'appendChild' on 'Node': Nodes of type '#document' may not be inserted inside nodes of type 'TD'.Broiler
This solution creates a typeof Document, if you're looking for instanceof HTMLElement use the solution provided hereMccraw
E
263

You typically create a temporary parent element to which you can write the innerHTML, then extract the contents:

var wrapper= document.createElement('div');
wrapper.innerHTML= '<div><a href="#"></a><span></span></div>';
var div= wrapper.firstChild;

If the element whose outer-HTML you've got is a simple <div> as here, this is easy. If it might be something else that can't go just anywhere, you might have more problems. For example if it were a <li>, you'd have to have the parent wrapper be a <ul>.

But IE can't write innerHTML on elements like <tr> so if you had a <td> you'd have to wrap the whole HTML string in <table><tbody><tr>...</tr></tbody></table>, write that to innerHTML and extricate the actual <td> you wanted from a couple of levels down.

Eschar answered 23/6, 2010 at 18:0 Comment(10)
+1 this solution is likely more portable.Wein
Keep in mind that this method will lose any event handlers or other properties that were assigned to it beforehand.Oestrogen
@Oestrogen how does a string would have event handlers attached to it/Padraic
@Muhammad - perhaps by using something like onclick="..." although that won't work for event handlers not defined in the HTML of course, which is perhaps what you meant.Punkah
what if the string is like this some string at the start <div><a href="#">anchor text</a><span>inner text</span></div>string end?Dehiscent
This doesn't support HTML strings containing an <body> elementBritzka
For complete fidelity, call div.remove(); so that div.parentNode reflects the intention of what the dom is supposed to represent.. if you attach it immediately to another dom node then it won't much matter, but for the sake of fidelity, div.remove(); is a good extra measure.Encode
DOMParser made some errors in parsing but it worked perfect.Aegeus
@Dehiscent you can use this for html scripts containing <body> if you use document.createElement('html')Lifelong
This solution creates a typeof HTMLElement, if you're looking for instanceof Document use the solution provided hereMccraw
A
85

Why not use insertAdjacentHTML

for example:

// <div id="one">one</div> 
var d1 = document.getElementById('one'); 
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');

// At this point, the new structure is:
// <div id="one">one</div><div id="two">two</div>here
Algiers answered 8/10, 2013 at 7:29 Comment(2)
You are aware that you would have this element to be in the DOM for this to work right? and you don't really want this element anyway in the DOM, you only want to convert a string into HTML in memoryBrouwer
Well, @vsync, that's certainly what the MDN docs say, but it sounds fishy since there's no reason for this function to care whether the target node is in the DOM or not. Using today's browser (Chrome), I just tested it and, nope, doesn't have to be in the DOM at all. Any node with a parent will make insertAdjacentHTML() happy as a clam. Wonder if any other browser behaves differently...Desmarais
A
17

Check out John Resig's pure JavaScript HTML parser.

EDIT: if you want the browser to parse the HTML for you, innerHTML is exactly what you want. From this SO question:

var tempDiv = document.createElement('div');
tempDiv.innerHTML = htmlString;
Apodal answered 23/6, 2010 at 17:57 Comment(2)
While writing an example I noticed that simple HTML tags render properly (on IE7) but when I try to do it with a script, which is the case i'm working on, the script doesn't work. Example: Fiddle. You might have to run the code on a local html page (jsfiddle doesn't work very well with IE7).Lumbard
This code has a minor issue: it doesn't work properly if htmlString likes to <tr>...</tr> :(Prearrange
P
6

Okay, I realized the answer myself, after I had to think about other people's answers. :P

var htmlContent = ... // a response via AJAX containing HTML
var e = document.createElement('div');
e.setAttribute('style', 'display: none;');
e.innerHTML = htmlContent;
document.body.appendChild(e);
var htmlConvertedIntoDom = e.lastChild.childNodes; // the HTML converted into a DOM element :), now let's remove the
document.body.removeChild(e);
Portcullis answered 23/6, 2010 at 18:0 Comment(1)
You don't need to add "e" to the document. You also don't need to do setAttribute on it.Roband
F
2

Here is a little code that is useful.

var uiHelper = function () {

var htmls = {};

var getHTML = function (url) {
                /// <summary>Returns HTML in a string format</summary>
                /// <param name="url" type="string">The url to the file with the HTML</param>

    if (!htmls[url])
    {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", url, false);
    xmlhttp.send();
    htmls[url] = xmlhttp.responseText;
     };
     return htmls[url];
    };

        return {
            getHTML: getHTML
        };
}();

--Convert the HTML string into a DOM Element

String.prototype.toDomElement = function () {

        var wrapper = document.createElement('div');
        wrapper.innerHTML = this;
        var df= document.createDocumentFragment();
        return df.addChilds(wrapper.children);
};

--prototype helper

HTMLElement.prototype.addChilds = function (newChilds) {
        /// <summary>Add an array of child elements</summary>
        /// <param name="newChilds" type="Array">Array of HTMLElements to add to this HTMLElement</param>
        /// <returns type="this" />
        for (var i = 0; i < newChilds.length; i += 1) { this.appendChild(newChilds[i]); };
        return this;
};

--Usage

 thatHTML = uiHelper.getHTML('/Scripts/elevation/ui/add/html/add.txt').toDomElement();
Fiscus answered 27/12, 2013 at 20:27 Comment(5)
Uhhh... This is basically just @orip's answer but with a lot of utterly unnecessary cruft added, in addition to extending the native String and HTMLElement prototypes (something you generally really shouldn't do). This is irrelevant bordering on dangerous...Amputate
@aendrew this is to different examples. The prototype helper happens to be one of the best helpers I've got in my entire solution(s) I pass in an array of DOM elements [ele,ele,ele,ele,ele], so I beg to differ. And also, the first convert to DOM Element is awesome as well. Learn more about the DocumentFragment, "Which no one ever uses" and you see what's going on. THESE ARE HELPERS, in a util file. This is what is wrong with developers' in todays' world, if it is not a 3rd party they're clueless. I write all my JS from scratch.Fiscus
And to expand on my last comment, performance is to be taken seriously in most of my JS apps.Fiscus
I'm simply saying don't pollute the prototype of builtins. That's considered best practice these days and has absolutely nothing to do with writing JS from scratch, using libraries, or performance — it's about preventing bugs further down the road.Amputate
@FillingTheStackisWhatIDO, what is the difference between returning wrapper.firstChild from toDomElement and returning df.addChilds(wrapper.children), apart from the fact that the later return an array of Nodes.Kop
M
1

Just give an id to the element and process it normally eg:

<div id="dv">
<a href="#"></a>
<span></span>
</div>

Now you can do like:

var div = document.getElementById('dv');
div.appendChild(......);

Or with jQuery:

$('#dv').get(0).appendChild(........);
Merla answered 23/6, 2010 at 17:31 Comment(5)
This is a jQuery example you gave. I think @rFactor was looking for a more straight up Javascript example.Ripple
@clarke78: Before down voting, you should have seen that i have already given an example of plain javascript.Merla
The example does not work, because it applies to already existing DOM elements. Of course the situation is simple if the element is already a DOM element, but in my situation the HTML contents is the value of a variable, not part of the DOM.Portcullis
@rFactor - are you willing/able to use jQuery? Parsing a string of HTML into DOM elements is very simple if you can use itYakut
I am not using jQuery, but anything jQuery can do can be done with plain JavaScript, so, if you have any examples, let me know. Hmm, actually I think I found the answer my self. :PPortcullis
D
1

You can do it like this:

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);
Demavend answered 3/5, 2013 at 0:8 Comment(0)
A
0

Summery:

  1. make an invisible element
  2. add the HTML in
  3. get the element by getting the first child of it

function txtToElem(txt){
let a = document.createElement('div')
a.style.display='none'
document.body.appendChild(a)
a.innerHTML=txt
let b = a.children
document.body.removeChild(a)
return b
}

let htmltext='<span>hello sir</span>'
console.log(txtToElem(htmltext))
//testing that it works as an elem:
document.body.appendChild(txtToElem(htmltext)[0])
<h1>the rest of the website...</h1>

First, append a div onto the document, which is made invisible by using the hide css proporty.

Then, append the text to the div to the invisble div by using appendChild()

Finally, get the elements inside the invisible div using the Element.children proporty

Note:

replace the a.children with a.childnodes to get nested elements too

Cons:

  1. Only works in frontend applications
Alkoran answered 22/6, 2023 at 10:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.