As dabblers in the dark arts of front-end development, an important topic we need to understand is this thing called UI Virtualization. This is a topic that frequently comes up in situations where we need to display a large amount of data in a performant way. In this article, we will learn more about what UI virtualization is, why it is important enough for us to spend time understanding it, and look at some popular implementations to see how it all works in the wild.
Here is the situation. Let's say we have a large amount of data we would like to display on screen:
Here is where things get interesting. The amount of HTML elements that we create and add to our DOM is directly related to the amount of data that we have. If we have a large amount of data that we need to visualize, we will have an explosion of HTML elements in our DOM. This is problematic because each element in our DOM takes up memory. Beyond just memory, our browsers do a lot of expensive work rendering each element, doing styling & layout calculations, running any related JS, and more.
If we want our pages to load quickly and respond snappily to our actions, having a bloated DOM does not help.
What's the solution here? How can we ensure we display data in a performant way? Hmm...
Independent of how large or small our data collection is, we know that there is only a finite amount of content we can see on screen:
Why waste resources trying to generate visuals for things we can't even see? The solution is to ensure we spend time generating the visuals only for the content we see and care about. This seemingly common sense approach is known as, you guessed it, UI virtualization. In a UI virtualized world, our application will constantly generate and discard our visuals to keep the contents of our DOM optimized for what we see on screen. This doesn't mean that a moment an element goes outside of our viewable area it gets discarded or that we render an element only when it hits our viewable area. There is a balance that we will need to strike between:
Fortunately, many UI virtualization solutions achieve this balance by rendering content for both what we see currently and a few screens worth of content that is just outside of what we see to account for any potential scrolling:
How far you go in implementing a good UI virtualization solution depends entirely on your needs: how much data needs to be displayed, how complex is the HTML that each item will be paired with, and so on.
Just like we don't want to waste resources rendering visuals that our users aren't likely to see, we also don't want to load a bunch of unnecessary data as well. The impact of loading excess data isn't quite as bad as generating excess visuals, but it is something to optimize as well. Loading extra data does mean we are storing more in memory, and depending on how the data is loaded into the page, it may mean you are taking up additional bandwidth to get the data in the first place. Optimizing the amount of data we load to only what is known as, wait for it, data virtualization! 🥳
A lot of our favorite data-heavy apps implement UI virtualization in some form or fashion. It would be difficult to list all of them, but if you've ever used Facebook, Twitter, Pinterest, Spotify, Google Maps, any Discourse forum (like this site's), and so on, you have run into it. When implemented well, we will rarely see the impact of UI virtualization in our regular browsing experience. We have to really look hard for it, and that might mean we scroll really quickly to get ahead of our browser in rendering content to the screen.
To give you an example, I loaded up Netflix and scrolled really quickly to help you see the edges where the visuals have not yet rendered. The following video highlights this, and I deliberately slowed down the video and added a callout at the 2 second mark to point out exactly where the visuals had yet to load:
If you weren't actively looking (and I had not slowed the video down), you may not have noticed Netflix's implementation of UI virtualization. They have done a good job providing a seamless experience. During normal Netflix browsing, the chances of you scrolling all the way down your page that quickly is also a very VERY rare thing.
Some sites like Pinterest are less subtle in their UI virtualization approach as the following video highlights:
The loading behavior for this additional content as we keep scrolling is very noticeable. Again, that's neither a good nor bad thing. There are many ways to implement UI virtualization to ensure our pages are performant when helping us visualize (a large amount of) data.
One more example. The kirupaForum's Discourse implementation of UI virtualization looks like this:
Because the data on the forums can easily be visualized as rows of content, the loading behavior simply appends more rows as we keep scrolling down. This has a fairly natural look with very little variation compared to the more complex layout of the items found in Pinterest. If there are other interesting examples of virtualization that you have found, please do share them by commenting below.
The number of things you can do to ensure your pages are really performant is almost endless. UI virtualization is just of those things that you can implement if you are in a situation where you have a lot of data that you need to visualize. Speaking of implementation, rolling your own UI virtualization solution is not the easiest of things in the world. My recommendation before you go down that dark and lonely and poorly documented path is to explore if any off-the-shelf community implementations of UI virtualization could be used instead. There are popular implementations for React, Vue, and even Vanilla JS that may suit your UI virtualization needs just perfectly.