IntersectionObserver Sample

Available in Chrome 51+ | View on GitHub | Browse Samples

Background

The IntersectionObserver API provides an API to understand the visibility and position of DOM elements relative to a containing element or to the top-level viewport.

This sample illustrates using IntersectionObserver to implement a infinite scroller without having to rely on scroll events. A sentinel element triggers the loading of additional elements once it comes into view and is being recycled after the new elements have been attached to the list.

The Google Developers Web Updates article provides more details on IntersectionObserver.

Live Output

On browsers that support IntersectionObserver, you should see a list that loads additional items as you scroll down.


CSS Snippet

.item {
  background: #FFF;
  border: 1px solid #666;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#sentinel {
  width: 1px;
  height: 1px;
}

#scroller {
  height: 400px;
  overflow-y: scroll;
}

JavaScript Snippet

/* global IntersectionObserver */
var scroller = document.querySelector('#scroller');
var sentinel = document.querySelector('#sentinel');
var counter = 1;

function loadItems(n) {
  for (var i = 0; i < n; i++) {
    var newItem = document.createElement('div');
    newItem.classList.add('item');
    newItem.textContent = 'Item ' + counter++;
    scroller.appendChild(newItem);
  }
}

var intersectionObserver = new IntersectionObserver(entries => {
  // If the browser is busy while scrolling happens, multiple entries can
  // accumulate between invocations of this callback. As long as any one
  // of the notifications reports the sentinel within the scrolling viewport,
  // we add more content.
  if (entries.some(entry => entry.intersectionRatio > 0)) {
    loadItems(10);
    // appendChild will move the existing element, so there is no need to
    // remove it first.
    scroller.appendChild(sentinel);
    loadItems(5);
    ChromeSamples.setStatus('Loaded up to item ' + counter);
  }
});
intersectionObserver.observe(sentinel);