JSFiddle - React, Tailwind, and code Playground

by Retsam19

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/1.2.2/bluebird.js"></script>
<script type="text/html" id="flex">
    <div class="label" data-bind="
        text: label">
    </div>
    <div class="children">
    <!-- ko foreach: {
        data: children,
        as: 'child'
    } -->
        <div class="outer" data-bind="
            template: {
                name: 'flex',
                data: child
            }
        ">
        </div>
    <!-- /ko -->
    </div>
</script>

<div>
    <h4>To see the rendering delay, open dev tools and resize viewport by sliding dev tools view divider quickly and repeatedly.  In chrome there is no delay.  In firefox version &lt; 38 there is a delay due to inefficient rendering calculations.</h4>

    <label>
        Number of nested flex elements:
        <input type="number" data-bind="
            value: nestedNumber
        "></input>
    </label>
    <br>
    <label class="old-flex-toggle-label">
        <input type="checkbox" data-bind="
            checked: useOldFlex
        "></input>
        Use old mozilla prefixes (2009 -- display: -moz-box). This only has an affect if you're using Firefox version &lt; 38.0 (red background on DOM body).  You'll notice there is no longer a rendering delay, but the behavior is not exactly the same and the flexbox terminology is somewhat different.
    </label>
<div>

<div class="outer">
    <iframe data-bind="
        iframe: {
            name: 'flex',
            data: root
        }
    "></iframe>
</div>

CSS

body {
        background-color: #eee;
        color: #222;
        display: flex;
        flex-direction: column;
        height: 600px;
        padding: 50px;
        white-space: normal;
        overflow-wrap: break-word;
        word-wrap: break-word;
    }
    html[data-is-affected-firefox="true"] body {
        background-color: red;
    }

    .old-flex-toggle-label {
        display: none;
    }
    html[data-is-affected-firefox="true"] .old-flex-toggle-label {
        display: inline;
    }

    .outer {
        background-color: #aaa;
        padding: 3px;
        outline: solid 1px;
        display: flex;
        flex-direction: row;
        align-items: stretch;
        justify-content: space-around;
        flex: 1 1 100px;
    }
    html[data-use-old-flex="true"] .outer {
        display: -moz-box;
        -moz-box-orient: horizontal;
        -moz-box-pack: justify;
        -moz-box-align: stretch;
        -moz-box-flex: 1;
    }
    .label {
        background-color: #eee;
        padding: 1px;
        display: flex;
        flex-direction: column;
        align-items: stretch;
        justify-content: space-around;
        flex: 0 0 8px;
    }
    html[data-use-old-flex="true"] .label {
        display: -moz-box;
        -moz-box-orient: vertical;
        -moz-box-pack: justify;
        -moz-box-align: stretch;
        -moz-box-flex: 1;
    }
    .children {
        background-color: #ccc;
        padding: 3px;
        display: flex;
        flex-direction: row;
        align-items: stretch;
        justify-content: space-around;
        flex: 1 1 100px;
    }
    html[data-use-old-flex="true"] .children {
        display: -moz-box;
        -moz-box-orient: horizontal;
        -moz-box-pack: justify;
        -moz-box-align: stretch;
        -moz-box-flex: 1;
    }

JavaScript

var ua = navigator.userAgent;
    var uaTokens = ua.split(' ');
    var lastToken = uaTokens[uaTokens.length-1];
    var isAffectedFirefox = false;
if (_.contains(lastToken, 'Firefox')) {
    var li = lastToken.split('/');
    // if user agent string says it's a firefox version under 38
    //   then we should use 2009 version of flexbox
    isAffectedFirefox = parseFloat(li[li.length-1]) < 38;
}
if (isAffectedFirefox) {
    $('html').attr('data-is-affected-firefox', isAffectedFirefox);
}
$('html').attr('data-use-old-flex', false);

var FlexViewModel = function (label, children) {
    var self =  this;
    self.label = label + '';
    self.children = children;
};

var ViewModel = function () {
    var self =  this;
    self.nestedNumber = ko.observable(20);
    self.useOldFlex = ko.observable(false);
    self.useOldFlex.subscribe(function () {
        $('html').attr('data-use-old-flex', self.useOldFlex());
    });
    
    self.root = ko.computed(function () {
        var depth = self.nestedNumber();
        rootChildren = _.range(depth).reduceRight(function (num, children) {
            return [new FlexViewModel(children, num)];
        }, []);
        return new FlexViewModel("R", rootChildren);
    });
};

ko.bindingHandlers.iframe = {
    init: function(element, valueAccessor) {
        
        function getTemplateId(value) {
            return (typeof value === "object") ?
                ko.unwrap(value.name) :
                value;
        }
        
        function getData(value) {
            return (typeof value === "object") && value.data ?
                value.data :
                ko.dataFor(element);
        }
        
        var value = valueAccessor();
        //Get the template
        var templateId = getTemplateId(value);
        template = document.getElementById(templateId);
        
        //Write the contents of the template to the iframe
        element.contentDocument.open();
       ...