JSFiddle - React, Tailwind, and code Playground

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js"></script>

<div data-bind="template: {afterRender: hide}">
    <div data-bind="html: html"></div>
</div>

<div id="spinner" style="display: none">Loading...</div>

<button onclick="go()">Go!</button>

CSS

#spinner {
    position: absolute;
    top: 20px;
    left: 20px;
    background-color: white;
    border: 1px solid green;
}

JavaScript

// Use a non-observable array to build the 3000 items
plain_items = [];

// Build 3000 items, which is enough to make my Macbook Air block for 3 seconds to render
// the simple template above.
for (var i = 0; i <= 5000; i++) {
    plain_items.push(i)
}

// Put the items in a VM
list = function() {
    this.items = ko.observableArray()
    
    this.html = ko.computed(function() {
        var html = "", i = 0, item
        for (i = 0; i < this.items().length; i++) {
            var item = this.items()[i];
            html = html + "<div>" + item + "</div>"
        }
        return html;
    }, this)
}
vm = new list()

// Trigger the rendering from a button click
go = function() {
    // Show the spinner immediately...
    $("#spinner").show();
    
    // ... by using a timeout.
    window.setTimeout(function() {
        ko.applyBindings(vm) 
        vm.items(plain_items)
    }, 1)
}

// Hide the spinner by applying this function to a template: {afterRender: ...} binding
hide = function() {
    $("#spinner").hide()
}