JSFiddle - React, Tailwind, and code Playground

HTML

<link rel="stylesheet" href="http://jlongster.com/s/bloop/app4/app.css">
<script src="http://cdn.jsdelivr.net/mithril/0.1.13/mithril.min.js"></script>

JavaScript

//model
var app = {}
app.state = {pageY: 0, pageHeight: window.innerHeight}

var items = []
for(var i = 0; i < 5000; i++) {
	items.push({
		title: 'Foo Bar ' + i
	})
}

//yes, window.innerHeight is a data source, so it goes in the model
window.addEventListener("scroll", function(e) {
	app.state.pageY = Math.max(e.pageY || window.pageYOffset, 0);
	app.state.pageHeight = window.innerHeight;
	m.redraw() //notify view
})

//controller
app.controller = function() {
	this.items = items
}

//view
app.view = function(ctrl) {
	var pageY = app.state.pageY
	var begin = pageY / 31 | 0
	// Add 2 so that the top and bottom of the page are filled with
	// next/prev item, not just whitespace if item not in full view
	var end = begin + (app.state.pageHeight / 31 | 0 + 2)

	var offset = pageY % 31
	
	return m(".list", {style: {height: ctrl.items.length * 31 + "px", position: "relative", top: -offset + "px"}}, [
		m("ul", {style: {top: app.state.pageY + "px"}}, [
			ctrl.items.slice(begin, end).map(function(item) {
				return m("li", item.title)
			})
		])
	])
}

m.module(document.body, app)