Left ArrowBack

notes / JavaScript / Web API / intersection observer

intersection observer

3 squares in a column. The middle highlighted & on top of a 4th square.

Intersection Observer


Status: seed

The Intersection Observer is a Web API that allows you to execute a callback whenever a target element starts or stops intersecting with the root (the viewport or another specified element).



const target = document.querySelector('#target')

const options = {
  rootMargin: '0px',
  threshold: 1,

function callback(entries, observer) {
  const { isIntersecting } = entries[0];
  console.log(`Is element 100% visible: ${isIntersecting}`)

const observer = new IntersectionObserver(callback, options);



When creating an observer, new IntersectionObserver(callback, options), an options object is required. It has 3 properties:


const options = {
    root: null,
    rootMargin: '0px',
    threshold: 1,


This can be set to:

  • the browser's viewport by setting a value of null (or omitting the property) or
  • an ancestor element of the target element.


A value that grows or shrinks the root's intersection area. It accepts values similar to the CSS margin property. Example: 32px 16px. Accepts pixels or percentages.


const options = {
    rootMargin: "-48px 0",
    threshold: 1,
Is intersecting: false


The percent of the target needed to intersect the root required to execute the callback. Represented as a value between 0 & 1. A value of 0.2 means when 20% of the target starts intersecting the root, the callback is executed. It will also execute when the target transitions from having more than 20% intersection to less than 20%.


const options = {
    rootMargin: "-48px 0",
    threshold: 0.2,
Is intersecting: false

A threshold value of 0 means the callback will execute when 1px of the target intersects. It can also be set to an array of numbers. Example: [0.2, 0.4, 0.6, 0.8]


The callback is executed when:

  • when a target is initially passed to the observer: observer.observe(target), or
  • a target starts (or stops) intersecting the root.

It receives 2 arguments:

  • entries: a list of IntersectionObserverEntry for each target which reported a change in its intersection status.
  • observer: the observer.


function callback(entries, observer) {
  entries.forEach((entry) => {
    const {
    } = entry


The callback is executed on the main thread. If it is expensive & could degrade the UX (User Experience) by blocking the browser, use requestIdleCallback.

Use Cases

  • Infinite Scroll
  • Table of Contents
  • Lazy-load content when scrolled into view
  • Start / stop animations entering / leaving the viewport
  • Reporting visibility of advertisements to calculate ad revenues
  • Drag & Drop
  • Changing color of fixed elements to maintain aria contrast requirements

Where to Next?

A sci-fi robot taxi driver with no lower body