JSFiddle - React, Tailwind, and code Playground

by Dan Bonelli

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
Scroll position: <span data-bind="text: scrollPosition"></span>

<div class="longdiv">    
    <p data-bind="scroll: scrollPosition">This is some text.</p>
    <div class="shim"></div>
</div>

CSS

.longdiv {
    width: 200px;
    height: 200px;
    overflow: auto;
    border: 1px solid black;
}

.shim {
    height: 1000px;
}

JavaScript

function scrollable(element) {
    var vertically_scrollable, horizontally_scrollable;
    
    var e = $(element);
    
     if (   e.css('overflow') == 'scroll' 
         || e.css('overflow') == 'auto'
         || e.css('overflowY') == 'scroll'
         || e.css('overflowY') == 'auto'
         || e.css('height') != 'none'
         || e.css('max-height') != 'none'                          
         ) {
         return true;
    } else {
        return false;
    }
}

ko.bindingHandlers.scroll = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var firstScrollableContainer = null;
        
        var binding = allBindings.get('scroll');
        
        $(element).parents().each(function (i, parent) {
            if (scrollable(parent)) {
                firstScrollableContainer = parent;
                return false;
            }
        });

        firstScrollableContainer = firstScrollableContainer || window;                
                
        binding(element.getBoundingClientRect().top);        

        var handler = function() {            
            binding(element.getBoundingClientRect().top);
        };
        
        if (firstScrollableContainer !== window) {
            $(firstScrollableContainer).scroll(handler);
        }
        
        $(window).scroll(handler);        
    }
};

var ViewModel = function() {
    var self = this;
    
    self.scrollPosition = ko.observable(0);
};

ko.applyBindings(new ViewModel());