JSFiddle - React, Tailwind, and code Playground

by tonyleeper

HTML

<div class="grid"></div>

CSS

html, body {
    font: 18px arial;
}
.grid {
    width: 300px;
    height: 300px;
    overflow: auto;
    border: 1px solid black;
}

.grid .row {
    border-bottom: 1px solid gray;
}

.grid .cell {
    border-right: 1px solid gray;
}

JavaScript

var VirtualGrid = function (element, params) {
    this.element = element;
    this.data = params.data;

    this.cellWidth = params.cellWidth;
    this.cellHeight = params.cellHeight;
    this.cellRenderer = params.cellRenderer;

    this.virtualHeight = this.data.length * this.cellHeight;
    this.virtualWidth = this.data[0].length * this.cellWidth;

    this.render();
};

VirtualGrid.prototype.render = function () {
    // render wrapper div with the correct width/height for the real physical scrollbar
    var html = '<div style="position: relative; width: ' + this.virtualWidth + 'px; height: ' + this.virtualHeight + 'px; overflow: hidden;">';

    // render rows
    for (var r = 0; r < this.data.length; r++) {
        var top = r * this.cellHeight;
        html += '<div class="row" style="position: absolute; height: ' + this.cellHeight + 'px; top: ' + top + 'px; left: ' + 0 + 'px">';

        // render columns
        for (var c = 0; c < this.data[r].length; c++) {
            var left = c * this.cellWidth;
            html += '<div class="cell" style="position: absolute; width: ' + this.cellWidth + 'px; height: ' + this.cellHeight + 'px; top: ' + 0 + 'px; left: ' + left + 'px">';
            html += this.cellRenderer(this.data[r][c]);
            html += '</div>';
        }

        html += '</div>';
    }

    html += '</div>';

    this.element.innerHTML = html;
};

var data = [];
for (var r = 0; r < 100; r++) {
    var rowData = [];
    for (var c = 0; c < 100; c++) {
        rowData.push('row' + r + ',col' + c);
    }
    data.push(rowData);
}

var grid = new VirtualGrid(document.getElementsByClassName('grid')[0], {
    data: data,
    cellWidth: 100,
    cellHeight: 50,
    cellRenderer: function (cell) {
        return cell;
    }
});

//#region EventCoordinator

var EventCoordinator = function (context) {
    this.context = context;
    this.registeredEventListeners = [];
};

EventCoordinator.prototype.register = function (element, type, listener,...