JSFiddle - React, Tailwind, and code Playground

by Sub Lines

HTML

<div class="observer__target"></div>
<span class="observer__state">Scroll Down</span>

CSS

body {
  margin: 0;
  height: 300vh;
}

.observer__target {
  position: relative;
  width: 80%;
  height: 50vh;
  margin: 200vh auto;
  background: rebeccapurple;
}

.observer__state {
  position: fixed;
  top: 1em;
  left: 1em;
  color: #fff;
  font: 400 1.125em/1.5 sans-serif;
  background: black;
  padding: .5em;
}

JavaScript

const state = document.querySelector('.observer__state')
const target = document.querySelector('.observer__target')

const thresholdArray = steps => Array(steps + 1)
 .fill(0)
 .map((_, index) => index / steps || 0)

let previousY = 0
let previousRatio = 0

const handleIntersect = entries => {
  entries.forEach(entry => {
    const currentY = entry.boundingClientRect.y
    const currentRatio = entry.intersectionRatio
    const isIntersecting = entry.isIntersecting

    // Scrolling down/up
    if (currentY < previousY) {
      if (currentRatio > previousRatio && isIntersecting) {
        state.textContent ="Scrolling down enter"
      } else {
        state.textContent ="Scrolling down leave"
      }
    } else if (currentY > previousY && isIntersecting) {
      if (currentRatio < previousRatio) {
        state.textContent ="Scrolling up leave"
      } else {
        state.textContent ="Scrolling up enter"
      }
    }

    previousY = currentY
    previousRatio = currentRatio
  })
}

const observer = new IntersectionObserver(handleIntersect, {
  threshold: thresholdArray(20),
})

observer.observe(target)