JSFiddle - React, Tailwind, and code Playground

by Константин Дралюк

HTML

<div class="list">
    <div class="sticky"></div>
    <div class="item">Item 1</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div class="item">Item n</div>
    <div...

CSS

.list {
    height: 400px; /* Or whatever height you need */
    overflow-y: auto;
    position: relative;
}

.sticky {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%; /* Adjust as needed */
    height: 50px; /* Adjust as needed */
    background-color: #ddd; /* For visibility */
}

JavaScript

const list = document.querySelector('.list');
let targetScrollTop = list.scrollTop;
let currentScrollTop = list.scrollTop;
let rafId = null;

list.addEventListener('wheel', function(event) {
    targetScrollTop += event.deltaY;

    // Ensure targetScrollTop remains within valid range
    targetScrollTop = Math.max(0, Math.min(targetScrollTop, list.scrollHeight - list.clientHeight));

    if (!rafId) {
        rafId = requestAnimationFrame(animateScroll);
    }

    event.preventDefault();
}, { passive: false });

function animateScroll() {
    const speed = 0.1; // Adjust this for faster/slower interpolation

    // Simple linear interpolation to smooth out the scroll
    currentScrollTop += (targetScrollTop - currentScrollTop) * speed;

    list.scrollTop = currentScrollTop;

    // Continue animation until current and target are almost equal
    if (Math.abs(currentScrollTop - targetScrollTop) > 0.5) {
        rafId = requestAnimationFrame(animateScroll);
    } else {
        cancelAnimationFrame(rafId);
        rafId = null;
    }
}