Skip to content

Intersection Observer Animation


Using Intersection Observer and Tailwind for a "fade-in and up" animation.

  const fadeinupList = document.querySelectorAll(".fadeinup")

  const callback = (entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {"translate-y-6", "opacity-0", "sm:translate-y-4", "sm:opacity-0")

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

  const observer = new IntersectionObserver(callback, options)

  fadeinupList.forEach(item => {


  1. Add the above js at the bottom of the page.

  2. Add the fadeinup class to any element that will be animated.

  3. The animated element needs the transition settings for the initial state.

Classes to add for basic example:

transition transform translate-y-6 opacity-0 fadeinup

Responsive example, with delay:

transition transform sm:delay-300 sm:translate-y-4 sm:opacity-0 fadeinup

In the above example the delay is only applied on breakpoints sm and up. This is useful when we want a slight delay on additional columns, but on mobile there is no delay.

In this example, the fade-in and translate-up are also only applied on breakpoints sm and up.

Be sure that all the classes are set to be removed to affect the animation."translate-y-4", "opacity-0", "sm:translate-y-4", "sm:opacity-0")


rootMargin: '-100px' means the element will need to be scrolled 100px into the viewport before it is triggered.

threshold of 0 means as soon as any part of the element is visible it will be triggered. A value of 1 means the entire element must be visible to be triggered. Or it can be any fraction e.g. 0.5

Based on the Introduction to scroll animations with Intersection Observer tutorial.

Stagger Animation

Tailwind CSS to add for a three column staggered animation from md breakpoint. With a three column layout this will add a 250ms delay to the items in the second column and a 500ms delay to the items in the third column.

<div class="grid md:grid-cols-12 md:[&>*:nth-child(3n+2)]:delay-150 md:[&>*:nth-child(3n)]:delay-300">

  <div class="md:col-span-4">Col 1</div>
  <div class="md:col-span-4">Col 2</div>
  <div class="md:col-span-4">Col 3</div>


Here is an example where it goes from one column, to three column and then finally to four column. Target a breakpoint range by stacking a responsive modifier like md with the max-* modifier for the next breakpoint.

<div class="grid md:grid-cols-12 

  <div class="md:col-span-4 xl:col-span-3">Col 1</div>
  <div class="md:col-span-4 xl:col-span-3">Col 2</div>
  <div class="md:col-span-4 xl:col-span-3">Col 3</div>
  <div class="md:col-span-4 xl:col-span-3">Col 1 (md) or Col 4 (xl)</div>


Intersection Observer API

How to Detect When a Sticky Element Gets Pinned