DEV Community

Cover image for Document Fragments and why you should use them
Abdulqudus Abubakre
Abdulqudus Abubakre

Posted on

Document Fragments and why you should use them

A document fragment is a fragment of a Document Object Model (DOM) tree, a chunk of tree that's separated from the rest of the DOM.
Before going further, let's talk about browser reflow and how it affects performance.

According to the google developers, reflow is the name of the web browser process for re-calculating the positions and geometries
of elements in the document, for the purpose of re-rendering part or all of the document.

Browser reflow can be caused by resizing the window,
changing the font, adding or removing a stylesheet, activation of a css psuedo-class, a script manipulating the DOM amongst others.
There are are several events other events that could trigger a browser reflow, but our main focus is the DOM manipulation from the script file.

Let's take for example the following data format gotten from restcountries api and we need to display each country, with its flag;

const countries = [
  {
    name: "Afghanistan",
    population: 27657145,
    flag: "https://restcountries.eu/data/afg.svg",
  },
  {
    name: "Åland Islands",
    population: 28875,
    flag: "https://restcountries.eu/data/ala.svg",
  },
  {
    name: "Albania",
    population: 2886026,
    flag: "https://restcountries.eu/data/alb.svg",
  },
];
Enter fullscreen mode Exit fullscreen mode

A simple approach to this would be:

  • loop over each element in the array
  • create a new element
  • append to an element in the DOM.

Here's how we would go about that in code.

// Select the parent element
const parentElement = document.querySelector('.countries');
// Loop over the array of countries and create each element
countries.forEach(country => {
    // Create a new div element
    const countryCard = document.createElement('div');
    // Create a new image element
    const img = document.createElement('img');
    // Set the src attribute of the image to the flag value from the data
    img.src = country.flag;
    // Attach the image to the div we initially created
    countryCard.appendChild(img);
    // Attach the card to parent element
    parentElement.appendChild(countryCard);
});
Enter fullscreen mode Exit fullscreen mode

Seems pretty simple and straightforward, and there seems to be nothing to worry about....if it's not broken, why fix it right?? 😃😃.

But under the hood, for every time we append the countryCard to the parentElement, we're causing a browser reflow. We might not notice any
glitch or drastic decline in performance in this case and that's because we only have three elements in the array, now imagine we had to the same thing for
all the countries and their individual states...you see where this is going?

Lucky for us, the browser provides a DocumentFragment object for us. As explained earlier, the document fragment is basically an interface
that represents a minimal document object (MDN).

It allows us perform actions we would normally perform on the actual DOM
but without the usual side effects, so we can easily create and append new elements without worrying about the numerous browser reflows that could
occur, and after we're done, we attach the fragment back into the DOM, hence only causing a single browser reflow as opposed to the hundreds or thousands of reflows we could have otherwise caused if we didn't use the fragment.

Now let's repeat the same thing we did above, but this time using the document fragment. The first thing we need to do is create the fragment.
That can be done using the DocumentFragment constructor or the createDocumentFragment method.

let fragment = new DocumentFragment();
// or let fragment = document.createDocumentFragment();
const parentElement = document.querySelector('.countries');
// Loop over the array of countries and create each element
countries.forEach(country => {
    // Create a new div element
    const countryCard = document.createElement('div');
    // Create a new image element
    const img = document.createElement('img');
    // Set the src attribute of the image to the flag value from the data
    img.src = country.flag;
    // Attach the image to the div we initially created
        countryCard.appendChild(img);
    // Append card to fragment element
    fragment.appendChild(countryCard);
});
// After iterating, we then insert fragment contents into the DOM
parentElement.appendChild(fragment);
Enter fullscreen mode Exit fullscreen mode

Something really interesting about the DocumentFragment is that the contents of the fragment are actually moved into the DOM, leaving behind
an empty DocumentFragment.
So you don't really have to worry about memory consumption....pretty awesome right? 😉😉

The document fragment is just one of many ways we could improve browser performance. There are several other techniques we could use to improve
performance of our web application

Top comments (13)

Collapse
 
isaachagoel profile image
Isaac Hagoel

Beside the additional div in the Dom tree, what is the different between creating the fragment and creating a div (using createElement) and appending all of the elements to it before finally appending it to the Dom? As long as the parent div is not in the Dom there will be no reflows, right?

Collapse
 
ibn_abubakre profile image
Abdulqudus Abubakre

Well, as you rightly mentioned, there's the fact that you'd be creating an additional element, which might or might not be what you wanted to achieve.
Also when using fragments, the children are effectively moved into the DOM and leaves behind an empty fragment.
But then again, they both serve the same purpose, and whatever works for you is fine. Some people would suggest using the createElement cause it's faster, some would say to use the DocumentFragment cause it was built for this

Collapse
 
yogeshdatir profile image
Yogesh Datir

If this has to be done multiple times, it will only create an untidy DOM tree with lots of empty divs. Then this will affect accessing DOM elements. For the same reason react also introduced Fragments.

Collapse
 
raddevus profile image
raddevus

Thanks for writing this up. It was really great.

This was such a great article that it inspired me to create a simple example CodePen for it.
You can check it out at : codepen.io/raddevus/pen/WNQbOpK
It looks like this:
Country Flags via CodePen

Collapse
 
ibn_abubakre profile image
Abdulqudus Abubakre

This is really amazing. Good work with the display 👌🏻

Collapse
 
sumitsood3127 profile image
sumeet sood

We can store the elements in array and after completing loop call append method with array.
`

`
function getListContent() {
let result = [];

for(let i=1; i<=3; i++) {``
let li = document.createElement('li');
li.append(i);
result.push(li);
}

return result;
}

ul.append(...getListContent()); // append + "..." operator = friends!
``

Collapse
 
aibee profile image
Iboro

Performance is such an important issue so this is just great. I particularly love that the fragment acts as a temporary storage and empties itself automatically after use.

Collapse
 
fleshmecha profile image

This is seriously brilliant. I needed this.

Collapse
 
ibn_abubakre profile image
Abdulqudus Abubakre

Really glad I could be of help

Collapse
 
deven96 profile image
Diretnan Domnan

Pretty neat writeup. I didn't for once consider optimizing for reflow

Collapse
 
ankittanna profile image
Ankit Tanna

Nice one

Collapse
 
ibn_abubakre profile image
Abdulqudus Abubakre

Thanks a lot

Collapse
 
codefinity profile image
Manav Misra

🤔 I 🤔 using TEMPLATE 🏷 can alleviate some of this too.