![]() |
A DocumentFragment node is treated specially in many DOM algorithms. In this article we will see some of the API methods that are designed for use in conjunction with the DocumentFragment. We will also see that the concept of node containers is important for other modern web technologies, such as the <template> element or the whole shadow DOM API. But before we start we should have a quick look at fragment parsing, which is not directly related to the DocumentFragment.
Fragment Parsing
An HTML5 parser can be used for more than just parsing a complete document. It can also be used for parsing a part of a document, called a fragment. Setting properties such as innerHTML or outerHTML will trigger fragment parsing. Fragment parsing works similar to regular parsing with a few exceptions. The biggest difference is the need for a contextual root.
The fragment that is being parsed is likely placed as the child of some element, which may or may not have additional ancestors. This information is crucial to determine the current parsing mode, which depends on the current tree’s hierarchy. Additionally, fragment parsing will not trigger script execution due to security reasons.
We may therefore use code like the following, but we won’t see the additional output. The script execution won’t be triggered.
- var foo = document.querySelector('#foo');
- foo.innerHTML = '<b>Hallo World!</b><script>alert("Hi.");</script>';
Clearly this depends on the case. For a particular scenario, Grgur Grisogono did the work to compare the performance using several methods. It also depends highly on the browser, especially how fast the JavaScript engine is. A higher value means more operations and is therefore desired.
![]() |
Aggregate DOM Operations
The idea behind the DocumentFragment node is simple: a container for Node objects. When a DocumentFragment is appended, it is expanded to append only the contents of the container, not the container itself. When a deep copy of a DocumentFragment is requested, its content is cloned as well. The container itself will never be attached to another node, even though it has to have an owner, which is the document that created the fragment.
Creating a DocumentFragment works as follows:
- var fragment = document.createDocumentFragment();
Templating in HTML
If document fragments are so great, why not use them for templating? Well, a DocumentFragment cannot be constructed in plain HTML, as the concept is only exposed via the DOM API. It is therefore only possible to create containers in JavaScript. This reduces the usage benefits a lot. Right now the most popular approach is still text-oriented. We start by placing our template in a pseudo <script> element. The element is pseudo, because the type attribute will be set to an invalid mime-type. This way nothing will be executed, but the text content of the element will use different parsing rules.
![]() |
Let’s consider an example. We use three elements that are good representatives for each of the three remaining states. The <div> element is, as many others, in the parsed characters (PCData) regime. The <textarea>, uses RCData like, e.g., the <title> element. Even more like raw characters is the Rawtext state, which could be represented by using a <style> element. There are subtle differences regarding escaping between the Rawtext and Script state. However, we will treat them as equivalent in the following discussion.
- var example = '<br>me & you > them';
- var types = ["div", "textarea", "script"];
- types.forEach(function (type) {
- var foo = document.createElement(type);
- foo.innerHTML = example;
- console.log(foo.innerHTML);
- })
- <br>me & you > them
- <br>me & you > them
- <br>me & you > them
The W3C recognized the situation and reacted by introducing the <template> element. The element can be understood as a DocumentFragment carrier. Since the DocumentFragment does not participate directly in the DOM tree, it is attached to a node via a property. Using the element is as easy as the following example:
- <template>
- <img src="{src}" alt="{alt}">
- <div class="comment">{comment}</div>
- </template>
Let’s get these children:
- var fragment = document.querySelector('template').content;
- var img = fragment.querySelector('img');
- var comments = fragment.querySelectorAll('.comment');
Let’s create a function to return the instantiated nodes for us. We tailor the code for the previous example.
- function createNodes (model) {
- var fragment = document.querySelector('template').content;
- var instance = fragment.clone(true);//deep cloning!
- var img = instance.querySelector('img');
- img.setAttribute('src', model.src);
- img.setAttribute('alt', model.alt);
- var div = instance.querySelector('div');
- div.textContent = model.comment;
- return instance;
- }
- var nodes = createNodes({
- src: 'image.png',
- alt: 'Image',
- comment: 'Great!'
- });
There are three important aspects of the <template> element:
- It triggers a different parsing mode. It is therefore more than just some element.
- Its children won’t be attached to the DOM, but to a DocumentFragment accessible via content.
- We have to make a deep copy of the fragment before we can use it.
The Shadow DOM
In recent years the demand for web components has exploded. Many of the front-end frameworks try to mimic a kind of web component structure. It is required, however, to have real DOM support, even though polyfills are certainly possible. The Polymer project is a good example of great polyfills, showcasing what could be done with web components.
What the shadow DOM allows us to do is to append a DocumentFragment to any Element. There are three constraints:
- The DocumentFragment has to be special—it has to be a ShadowRoot.
- Every Element can only have one ShadowRoot, or none of course.
- The contents of the ShadowRoot are separated from the original DOM.
One consequence of attaching a ShadowRoot to an element is that the element is not rendered any more—instead the content within the shadow DOM is rendered. The content is scoped, however, which means that it may follow its own styling rules. Also the whole event handling process is a little bit different.
As a result, another new concept has been introduced: slots. We can define slots in our shadow DOM, which are filled with nodes from the element, which hosts the ShadowRoot. It seems obvious that creating custom elements, which carry the shadow DOM, is a good idea. The whole custom elements specification is a reaction to that.
So how can we use the shadow DOM? Let’s do some JavaScript to reveal the API. We start with the following HTML fragment:
- <div id="#shadow-dialog">
- <span slot="header">
- My header title
- </span>
- <div slot="content">
- <strong>Some very important content</strong>
- </div>
- </div>
- var context = document.querySelector('#shadow-dialog');
- var root = context.attachShadow({ mode: 'open' });
- var headerSlot = document.createElement('slot');
- headerSlot.name = 'header';
- root.appendChild(headerSlot);
- var contentSlot = document.createElement('slot');
- contentSlot.name = 'content';
- root.appendChild(contentSlot);
- <div id="#shadow-dialog">
- <slot name="header">
- <span slot="header">
- My header title
- </span>
- </slot>
- <slot name="content">
- <div slot="content">
- <strong>Some very important content</strong>
- </div>
- </slot>
- </div>
Now some people may think that we had similar techniques already on the server-side. And of course some client-side frameworks also try to aggregate code like this. There are some key differences, however. First, we have the browser’s full support (if implemented). Second, the sandboxing makes rendering with specific rules for that module easy—no clash with existing CSS rules. It is essentially guaranteed that the module works on every page. No more debugging to see where the CSS rules interfere with each other. Finally, we produce much nicer code. It’s easy to generate and cheap to transport, and we can expect even better performance.
Conclusion
The DocumentFragment is a useful helper that has the ability to reduce the number of DOM operations drastically. It is also an important cornerstone of modern technologies, especially in the web components area. It has already generated two really outstanding technologies: the <template> element and ShadowRoot. While the former simplifies templating a lot, giving us a nice performance speedup and an elegant way to transport pre-generated nodes, the latter is the foundation for web components.
Is it really worth knowing about the DocumentFragment? Probably not yet. If we’re writing a framework or library then it is definitely a must, but most users will be happy that is very likely already used in their favorite front-end library, such as jQuery, Angular, and others. They all use the DocumentFragment in one or more places to overcome potential performance hits. Is a virtual DOM faster than the real one? Yes, of course, but it may not be as fast without using a DocumentFragment to aggregate multiple operations.
Written by Florian Rappl
If you found this post interesting, follow and support us.
Suggest for you:
Build Responsive Real World Websites with HTML5 and CSS3
Build Professional Websites with HTML5 and CSS3 from Scratch
Advanced HTML5 Tutorial for Web Developers
Coding Made Easy: HTML & CSS For Beginners
Easily Learn HTML 5 From Scratch



No comments:
Post a Comment