JavaScript List Virtualization Example
More info: https://ykamal.com/posts/2024-07-05-javascript-performance-tip-list-virtualization
by ykamal
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>Scorll down inside the list. <a target="_blank" href="https://ykamal.com/posts/2024-07-05-javascript-performance-tip-list-virtualization">Read More</a></p>
<div id="list-container"></div>
</body>
</html>
JavaScript
function createVirtualizedList(container, itemHeight, totalItems, renderItem) {
const visibleItems = Math.ceil(container.clientHeight / itemHeight) + 1;
const listHeight = totalItems * itemHeight;
let scrollTop = 0;
function setupContainer() {
container.style.overflow = 'auto';
container.style.position = 'relative';
const content = document.createElement('div');
content.style.height = `${listHeight}px`;
content.style.position = 'relative';
container.appendChild(content);
return content;
}
function render(content) {
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(startIndex + visibleItems, totalItems);
content.innerHTML = '';
const fragment = document.createDocumentFragment();
for (let i = startIndex; i < endIndex; i++) {
const item = renderItem(i);
item.style.position = 'absolute';
item.style.top = `${i * itemHeight}px`;
item.style.left = '0';
item.style.right = '0';
item.style.height = `${itemHeight}px`;
fragment.appendChild(item);
}
content.appendChild(fragment);
}
function handleScroll(content, event) {
const newScrollTop = event.target.scrollTop;
if (Math.abs(newScrollTop - scrollTop) > itemHeight / 2) {
scrollTop = newScrollTop;
requestAnimationFrame(() => render(content));
}
}
const content = setupContainer();
render(content);
container.addEventListener('scroll', (event) => handleScroll(content, event));
}
// Usage
const container = document.getElementById('list-container');
container.style.height = '400px';
container.style.width = '300px';
container.style.border = '1px solid black';
const itemHeight = 50;
const totalItems = 10000;
createVirtualizedList(
container,
itemHeight,
totalItems,
(index) => {
const item = document.createElement('div');
item.textContent = `Item ${index + 1}`;
item.style.border = '1px solid #ccc';
item.style.boxSizing =...