Why You Should Use Document Fragments

There are countless options to optimize performance, starting from image and font optimization, all the way to optimizing JavaScript.

A common scenario that can take a toll on your performance, is the heavy manipulation of the DOM. React solves this with a virtual DOM, which is a JavaScript representation of the real DOM tree. But what if you are not working in React? You want things to work smoothly in vanilla JavaScript.

Document Fragments might be what you are looking for. It is a web API that is used as a lightweight alternative to Document. It works just like the regular document, but initially, it has no parent. Therefore, the key difference between a document fragment and the real DOM, is that it is not part of the real DOM. It only becomes part of it, once you add it.


How Document Fragments Work

To create a new document fragment, all you have to do is call it with the new keyword:

new DocumentFragment();
Copied to clipboard!

If you initialize it in your DevTools and store it in a global variable, you will be able to see that it has all the methods you usually find on the real DOM, yet this is detached until you actually add it.

Inspecting a document fragment in DevTools
The same properties and methods you would find on a DOM element, are available on a DocumentFragment

What is the Benefit of Using it?

The most common use case you will find is when you need to construct a DOM subtree through JavaScript. For this, you can use a document fragment to prepare your elements and attach it to the real DOM once you are done. Because you insert everything once, you will only have one reflow and a single render.

Imagine you need to construct a dynamic list with a bunch of elements. If you interact with the real DOM, you potentially trigger a render and reflow for every node added. This can be avoided using document fragments.

Document fragments in action

Letโ€™s see an example of using them. Imagine you have the following unordered list in your DOM, and you want to populate it through JavaScript:

<ul id="list"></ul>
Copied to clipboard!

Without a document fragment, you would do it in the following way:

const unorderedList = document.getElementById('list');
const activities = ['๐Ÿ„', '๐Ÿšด', '๐Ÿคธ', '๐Ÿƒ'];

activities.forEach(activity => {
    const listItem = document.createElement('li');
  
    listItem.innerText = activity;
    unorderedList.appendChild(listItem);
});
populate.js
Copied to clipboard!

You get the element from the DOM and you loop through your data. For each entry, you create a new li element and append it to the list. Although this is heavily optimized internally by browsers, you are doing more interaction with the DOM than necessary. With document fragments, you would do it in the following:

const unorderedList = document.getElementById('list');
const activities = ['๐Ÿ„', '๐Ÿšด', '๐Ÿคธ', '๐Ÿƒ'];
const fragment = new DocumentFragment();

activities.forEach(activity => {
    const listItem = document.createElement('li');
  
    listItem.innerText = activity;
    fragment.appendChild(listItem);
});

unorderedList.appendChild(fragment);
populate.js
Copied to clipboard!

Again, the first two lines are the same; you get the DOM element and your data, but you also need to set up a new DocumentFragment. The loops almost look identical, but there is a big difference. As you can see, instead of appending each list element directly to the DOM, the loop attaches them to the fragment. After the loop, we attach the whole list only once to the list.

Note that when you append a fragment to the DOM, you are left with an empty fragment.

This means, you donโ€™t need to create a new fragment, you can reuse them same, multiple times.

For complex DOM subtrees, you also have the option to use a DOMParser. This can make your code more readable, and again, you donโ€™t interact with the real DOM for each node you make. However, note that it is not as efficient as using a document fragment.

const domContent = `
    <ul>
        ${activities.map(activity => `<li>${activity}</li>`).join('')}
    </ul>
`;

const parser = new DOMParser().parseFromString(domContent, 'text/html');

unorderedList.replaceWith(parser.getElementsByTagName('ul')[0]);
DOMParser.js
Copied to clipboard!

Conclusion

In conclusion, if you have to do heavy DOM manipulation, or you need to dynamically append items in loops, you can opt-in using document fragments to improve your performance. To see how each of the solutions perform, Iโ€™ve created a benchmark test that you can run on JSBench.me.

Benchmark results of document fragments

If you would like to learn more about performance optimization, make sure you continue your journey with the article below. Thank you for reading through, happy coding!

10 Critical Performance Optimization Steps You Should Take

๐Ÿ“š Get access to exclusive content

Want to get access to exclusive content? Support webtips to get access to tips, checklists, cheatsheets, and much more. โ˜•

Get access Support us
Read more on
๐ŸŽ‰ Thank you for subscribing to our newsletter. x