66

So I've been slowly replacing a lot of my normal jQuery code with native javascript, and I happened upon the document.createTextNode() and related MDN documentation. After reading I'm somewhat confused what a text node is.

I understand it can be used to put text inside div's, but I'm sure there's a bit more to it than just "use it to put words inside elements". Looking at this, it appears a text node can also refer to the text of attributes as well.

Can anyone provide a bit more of a definition of what a text node is and what it's used for? Are there practical uses for this other than basic stuff like this?

var div = document.createElement('div');
var text = document.createTextNode('Y HALO THAR');
div.appendChild(text);
AlbertEngelB
  • 16,016
  • 15
  • 66
  • 93
  • 11
    mostly, it's how we built dynamic HTML before innerHTML worked reliably. – dandavis Jun 19 '13 at 15:59
  • Ahhh, ok! I could see how that would require a workaround like this. – AlbertEngelB Jun 19 '13 at 16:05
  • @dandavis It is also more secure, especially where user input is concerned. – Xotic750 Jun 19 '13 at 16:19
  • @Xotic750 also, we have jQuery nowadays. jQuery is a nice thing to have :-) – John Dvorak Jun 19 '13 at 16:21
  • 1
    I'd just like to point out that while it may feel more "native" to use things like large tree loops using document.createElement, appendChild, and createTextNode, when doing this on macro levels, innerHTML can actually be faster (but has security risks in some cases, as Xotic said). The logic is that calling innerHTML once passes information directly to a specialized C++ parser, whereas manual create/append is doing manual work in a Javascript engine; they're fast, but still not quite as fast as the browser's code. – Katana314 Jun 19 '13 at 16:23
  • Wow, great information to know @Katana314, thanks! If we're talking non-user input, I'll definitely look to start using .innerHTML instead. – AlbertEngelB Jun 19 '13 at 16:29
  • 3
    @Katana regarding performance of the different methods, please see this [jsperf](http://jsperf.com/innerhtml-vs-textconten-vs-create-and-append-text-node) – Xotic750 Jun 19 '13 at 16:42
  • Xotic: Yup, for something like a single element, it's much slower. In cases of basic logic creating one or two elements, I prefer createElement (and it makes the code look cleaner). However, if you're putting together an entire popup with dozens of divs, based on an AJAX request, and have the option of either structuring the HTML bit-by-bit in Javascript using data provided, or just setting the entire HTML content at once, it's likely to work better doing it all at once as HTML. Plus, HTML is arguably easier to read than Javascript that slowly creates HTML. – Katana314 Jun 19 '13 at 17:28
  • @Xotic750: how is innerHTML any less secure than createElement/createTextNode? – dandavis Jun 19 '13 at 17:58
  • 1
    See [Security considerations of innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/element.innerHTML), createTextNode does not suffer this problem. – Xotic750 Jun 19 '13 at 18:01
  • i guess innerHTML is a larger gun, but you shouldn't arm maniacs with anything. createElement does the same things as innerHTML, it's just more obvious when you code something dumb long-handed/explicitly... – dandavis Jun 19 '13 at 18:08
  • 1
    [`createElement`](https://developer.mozilla.org/en-US/docs/Web/API/document.createElement) does not do the same things as [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/element.innerHTML) – Xotic750 Jun 19 '13 at 18:11
  • @dandavis I think it all comes down to what you're using to populate these elements. If you're getting values from a states DB entry that isn't changed by users, then I'd say it's pretty safe. When you're using .innerHTML() to put in an HTML string which gets values from a user's profile/ post (for example), then you could have users entering possibly malicious JS if you use .innerHTML(). I see where both are useful, for sure. – AlbertEngelB Jun 19 '13 at 18:31
  • You can XSS yourself, but [F12] is easier... my point is that user input should be scrubbed, and if that's done, then innerHTML is harmless. I would never echo back un-sanitized data and count on using textContent or textNodes to protect everyone in all venues, devices, and circumstances, like non-js users... – dandavis Jun 19 '13 at 20:41
  • @dandavis Right, you *should* sanitize the data before it ever gets stored, however this isn't always the case. I am going to guess that most times, if a user doesn't have JS enabled, you're not going to have to really worry about XSS (generally). – AlbertEngelB Jun 19 '13 at 21:05
  • @Dropped.on.Caprica style tags can ping outside sites, as can imgs, while meta tags can redirect, and flash and java can, well, you get the idea; XSS is way more than onmouseover attacks... – dandavis Jun 19 '13 at 21:15
  • @dandavis True, true. I say that because in this instance if a user doesn't have JS then they aren't going to be having that information populate for them. – AlbertEngelB Jun 19 '13 at 21:54
  • 2
    @Katana314 - There are actually cases too where using createDocumentFragment and cloneNode are significantly faster than innerHTML, if you're creating thousands of nodes with the same structure (like making a DOM number line or something) it's faster to create a documentFragment, append a hundred or so elements to it and clone that documentFragment a bunch of times. DocumentFragments and cloneNode are crazy performant. – hobberwickey Apr 14 '15 at 22:33
  • @hobberwickey Thanks. I never even knew about those functions. – Katana314 Apr 15 '15 at 13:24

2 Answers2

85

All viewable HTML text in a page (except text in form elements or custom embedded objects) is in text nodes. The page consists of a number of different types of nodes (you can see a listing of the different node types here: https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType), some of which can have child nodes and some of which cannot. For example, a div is an ELEMENT node which can contain child nodes. Those child nodes can be other ELEMENT nodes or they can be TEXT nodes or COMMENT nodes or other types of nodes.

When you set the .innerHTML property of an element node, it creates the appropriate nodes and makes them child nodes of the element that you set the innerHTML property on. If there is text in the innerHTML you set, then text nodes will be created to hold it.

DOCUMENT_NODE, ELEMENT_NODE and TEXT_NODE are the most common node types and are in every page that has text.

In your code example:

var div = document.createElement('div');
var text = document.createTextNode('Y HALO THAR');
div.appendChild(text);

This creates one text node and puts it into the div you created. It generates the same DOM structure as this:

var div = document.createElement('div');
div.innerHTML = 'Y HALO THAR';

In the latter case, the system creates the text node for you.


In plain javascript programming (jQuery tends to shield developers from nodes that aren't of type ELEMENT_NODE), you will encounter text nodes any time you walk the child nodes of an element that has text in it. You will need to check the .nodeType of each child to know whether it is another element or a text node or some other type of node.


In general, there aren't a lot of reasons to manipulate text nodes directly as you can often use the higher level .innerHTML property more simply. But, to give you an idea, here are a couple reasons you might want to deal directly with text nodes:

  1. You want to change some text without affecting any of the elements around it. .innerHTML creates all new elements for the affected elements which kills any event handlers which might have been set on them, but setting the .nodeValue on a text node doesn't cause any elements to get recreated.

  2. If you want to find just the text in a document without any of the resulting HTML markup and know exactly where each piece of text is in the DOM hieararchy, you can just search for all the text nodes. For example, if you were doing a text search of the document and then highlighting found text, you would probably search text nodes directly.

  3. You want to display some text without any security risks that it might contain other markup that the browser would parse and interpret if you used .innerHTML. So, you create a text node and set the value of its text and the browser won't interpet any HTML in it. Modern browsers can also use the .textContent property of an element instead of .innerHTML to solve this problem too.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 15
    On modern browsers it is worth mentioning `textContent`, "it is recommended you not use innerHTML when inserting plain text; instead, use element.textContent. This doesn't interpret the passed content as HTML, but instead inserts it as raw text." – Xotic750 Jun 19 '13 at 16:28
  • 2
    "All viewable text in a page is in text nodes." No, it could also come from the `content` property in a `::before` or `::after` CSS rule. –  Jul 19 '13 at 13:07
  • 2
    "All viewable text in a page is in text nodes" No, could also come form 'value' attrubute of `` or ` – Jasen Nov 25 '15 at 23:20
0

innerText get and set the content as plain text, encode and decode. When innerHTML get and set the content in HTML format.

var div = document.createElement('div');
div.innerText = 'Y HALO THAR';
Darlan Dieterich
  • 2,369
  • 1
  • 27
  • 37