JSFiddle - React, Tailwind, and code Playground

by rich_harris

HTML

<script src="http://cdn.ractivejs.org/edge/ractive.js"></script>
<main></main>

<script id='template' type='text/ractive'>
    <button class='addColumn' on-click='addColumn'>+</button>
    
    <table>
        <tr>
            {{#each columns}}
            <th><input value='{{name}}'/></th>
            {{/each}}
        </tr>
        
        {{#each rows:r}}
        <tr>
            {{#each columns}}
            <td><input value='{{rows[r][id]}}'/></td>
            {{/each}}
        </tr>
        {{/each}}
    </table>
    
    <button class='addRow' on-click='addRow'>+</button>
    
    <p>JSON:</p>
    <pre>{{JSON.stringify(rows,null,'  ')}}</pre>
</script>

CSS

body {
    font-family: 'Helvetica Neue', arial, sans-serif;
    font-weight: 200;
    color: #353535;
}

main {
    position: relative;
    padding: 0 6em 0 0;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

h1, h2, h3, h4, h5, h6 {
    font-weight: 200;
}

table {
    border-collapse: collapse;
}

th, td {
    text-align: left;
    border-bottom: 1px solid #ddd;
}

th {
    font-weight: bold;
}

td {
    border-left: 1px solid #eee;
}

td:last-child {
    border-right: 1px solid #eee;
}

input {
    display: block;
    width: 100%;
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    margin: 0;
    border: none;
}

.addColumn {
    position: absolute;
    right: 6em;
    width: 2.5em;
}

JavaScript

var uid = 0;

// sample data from http://learn.ractivejs.org/list-sections/1
var xmen = [
  { name: 'Nightcrawler', realname: 'Wagner, Kurt',     power: 'Teleportation',    info: 'http://www.superherodb.com/Nightcrawler/10-107/' },
  { name: 'Cyclops',      realname: 'Summers, Scott',   power: 'Optic blast',      info: 'http://www.superherodb.com/Cyclops/10-50/' },
  { name: 'Rogue',        realname: 'Marie, Anna',      power: 'Absorbing powers', info: 'http://www.superherodb.com/Rogue/10-831/' },
  { name: 'Wolverine',    realname: 'Howlett, James',   power: 'Regeneration',     info: 'http://www.superherodb.com/Wolverine/10-161/' }
];

var Table = Ractive.extend({
    template: '#template',
    import: function ( records ) {
        var columns = [], columnIdByName = {};
        
        // first, get columns
        records.forEach( function ( record ) {
            Object.keys( record ).forEach( function ( name ) {
                var columnId;
                
                if ( !columnIdByName[ name ] ) {
                    columnId = '_' + uid++;
                    columnIdByName[ name ] = columnId;
                    
                    columns.push({
                        id: columnId,
                        name: name,
                        
                        // TODO infer type, sensible default value
                        type: 'string',
                        defaultValue: function () { return null; }
                    });
                }
            });
        });
        
        // then, create rows using column IDs as property names
        rows = records.map( function ( record ) {
            var row = {};
            
            Object.keys( record ).forEach( function ( name ) {
                row[ columnIdByName[ name ] ] = record[ name ];
            });
            
            return row;
        });
        
        this.set({
            columns: columns,
            columnIdByName: columnIdByName,
           ...