JSFiddle - React, Tailwind, and code Playground

HTML

<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<p>All equations must start with a = character (like in Excel).</p>
<p>Use the # character to lookup variables and cell references in the equation editor.</p>
<hr>
<div id="dynamic-table-main">
    <div data-ng-controller="GridCtrl">
        <table class="table sheet table-bordered table-hover table-striped" id="grid">
            <thead></thead>
            <tbody>
                <tr ng-repeat="row in data.body">
                    <td ng-repeat="col in row" class="input-tooltip-wrapper">
                        <formula-editor value="col.value"></formula-editor> <span class="c-tooltip">{{compute(col)}}</span>

                        <div class="cell-view" ng-bind="compute(col) | cellFormatter" tabindex="{{ $parent.$index + $index }}" style="text-align: {{isNum(compute(col)) ? 'right' : 'left'}}"></div>
                    </td>
                </tr>
            </tbody>
        </table>
         <h3>Variables</h3>

        <div class="row">
            <div class="col-md-6">
                <table class="table variables table-bordered table-hover table-striped">
                    <tbody>
                        <tr ng-repeat="variable in variables">
                            <td class="variable-name">{{variable.name}}</td>
                            <td>
                                <input class="form-control" type="text" ng-model="variable.value" />
                            </td>
                            <td> <a href="#" ng-click="removeVariable(variable)" class="btn btn-danger">Remove</a> 
                            </td>
                        </tr>
                        <tr>
                            <form data-ng-submit="addVariable(newVar)">
                          ...

CSS

body {
    padding:50px 20px 20px 20px;
}
table.sheet {
    table-layout:fixed;
}
table.sheet .taggable-text-wrapper > div {
    outline: 0;
}
.input-tooltip-wrapper {
    position:relative;
}
/* .input-tooltip-wrapper:hover .c-tooltip{
    display:block
} */
 .taggable-text-wrapper:hover + .c-tooltip {
    display:block
}
.c-tooltip {
    display:none;
    position:absolute;
    min-width:100px;
    margin-left:0;
    line-height:30px;
    color:#fff;
    padding:0 5px;
    border-radius:4px;
    font-size:12px;
    background:rgba(0, 0, 0, 0.8);
    top:auto;
    bottom:150%;
    left:0;
    z-index:10;
    text-align:center;
    margin-top:0;
    transition:all 0.5s ease;
}
.c-tooltip:after {
    position: absolute;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
    display:block;
    content:" ";
    bottom: -6px;
    left:12px;
    margin-left: -6px;
    border-width: 6px 6px 0;
    border-top-color: rgba(0, 0, 0, 0.8);
}
table.sheet td {
    position: relative;
}
table.sheet th.index {
    width:10%;
}
table.sheet td .taggable-text-wrapper {
    display: none;
    position: absolute;
    left: -10px;
    right: 0;
    top: -10px;
    bottom: 0;
    width: 100%;
    height:100%;
    z-index:10;
}
table.sheet td .taggable-text-wrapper div {
    min-width:100%;
    min-height:34px;
    padding:15px;
    -webkit-box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.3);
    box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.3);
    background:#fff;
    border-radius:4px;
}
table.variables {
}
td.variable-name {
    font-size:18px;
    font-weight:bold;
    line-height:30px !important;
    vertical-align:middle;
}
table.variables .btn {
    min-width:100px;
}
.btn-tag-control {
    padding:0px 6px;
    margin:3px;
}

JavaScript

// =================================================
// LIBS

/*
 IntegraXor Web SCADA - JavaScript Number Formatter
 http://www.integraxor.com/
 author: KPL, KHL
 (c)2011 ecava
 Dual licensed under the MIT or GPL Version 2 licenses.
 */
window.format = function(b, a) {
    if(!b || isNaN(+a))return a;
    var a = b.charAt(0) == "-" ? -a : +a, j = a < 0 ? a = -a : 0, e = b.match(/[^\d\-\+#]/g), h = e && e[e.length - 1] || ".", e = e && e[1] && e[0] || ",", b = b.split(h), a = a.toFixed(b[1] && b[1].length), a = +a + "", d = b[1] && b[1].lastIndexOf("0"), c = a.split(".");
    if(!c[1] || c[1] && c[1].length <= d)a = (+a).toFixed(d + 1);
    d = b[0].split(e);
    b[0] = d.join("");
    var f = b[0] && b[0].indexOf("0");
    if(f > -1)for(; c[0].length < b[0].length - f;)c[0] = "0" + c[0]; else+c[0] == 0 && (c[0] = "");
    a = a.split(".");
    a[0] = c[0];
    if(c = d[1] && d[d.length -
        1].length) {
        for(var d = a[0], f = "", k = d.length % c, g = 0, i = d.length; g < i; g++)f += d.charAt(g), !((g - k + 1) % c) && g < i - c && (f += e);
        a[0] = f
    }
    a[1] = b[1] && a[1] ? h + a[1] : "";
    return(j ? "-" : "") + a[0] + a[1]
};

/*!
 * jquery.taggable-text.js
 *
 * Adapted from https://github.com/yuku-t/jquery-textcomplete
 */

(function() {
    var UtilityFunctions = {
        getSelection                      : function(containerEl) {
            // http://stackoverflow.com/a/13950376/564580
            var range = window.getSelection().getRangeAt(0);
            // /\ this is sometimes painful
            var preSelectionRange = range.cloneRange();
            preSelectionRange.selectNodeContents(containerEl);
            preSelectionRange.setEnd(range.startContainer, range.startOffset);
            var start = preSelectionRange.toString().length;

            if(typeof start === "undefined") {
                start = 0;
            }
            return {
                start : start,
                end   : start +...