JSFiddle - React, Tailwind, and code Playground

by baacke

HTML

<div class="bracket">
    <table>
        <tbody>
    <!-- APPEND HERE -->
        </tbody>
    </table>
</div>

CSS

.bracket table {border-collapse: collapse;
    border-spacing: 0;
    color: #000}

.bracket td {text-align: center;
    height: 25px;
    width: 200px;
    position: relative;}

.bracket td.winner {border: 0}

/*.bracket td div {height: 54%} Now Set Inline During Bracket Creation for IE8 Compatability */

.bracket td div.left{border-right: 2px solid #333;
    border-top: 2px solid #333;
    border-bottom: 2px solid #333;
    border-radius: 0 2px 2px 0}

.bracket td div.right{border-left: 2px solid #333;
    border-top: 2px solid #333;
    border-bottom: 2px solid #333;
    border-radius: 0 2px 2px 0}

.bracket td div.first,
.bracket td div.last {height: 95%}

.bracket td div.bye {display: none}

.bracket td div span {display: block;
    width: 100%;
    text-align: center;
    position: absolute;
    margin: 0 auto -11px;
    bottom: 50%;
    cursor: pointer}

.bracket td div.winner span {cursor: default}

.bracket td div span.tbd {cursor: default;
    color: #949494;
    font-size: 10px;
    margin-bottom: -5px;
    text-transform: uppercase}

JavaScript

var maxFullRoundGames = 1,
    rowsNeeded = null,
    colsNeeded = null,
    divHeight = 30; //in px (for IE8 height)
    tbody = $('div.bracket table tbody'),
    teams = [];
var totalTeams = /*teams.length - 2;*/ Number( prompt("how many teams?") );

for( ; (maxFullRoundGames * 2) < totalTeams ; )
{ maxFullRoundGames *= 2; }

var reqFirstRoundGames = totalTeams - maxFullRoundGames;
var reqFirstRoundByes = totalTeams - (reqFirstRoundGames * 2);

/* Determine Number of Table Rows Required */
if( totalTeams % maxFullRoundGames > 0  )
    { rowsNeeded = maxFullRoundGames; }
else
    { rowsNeeded = totalTeams / 2; }

/* Create Pattern for ColSpan */
var colPattern = [1];
for( var c = 2; c <= rowsNeeded; c *= 2 ){
    for ( var p = 0 ; p < c - (c / 2) ; p++ ){
        colPattern.push( colPattern[p] );
    }
    colPattern[0] = colPattern[0] + 1;
}

/* Define Pattern for Seeding */

var left = [],
    right = [];

for(var z = 1, i = 1, current = 'left' ; i <= rowsNeeded*2 ; i++){
    if( current == 'left' ){
        left.push(i)
    }else{ //current == 'right'
        right.push(i)
    }
    if( z == 1 ){
        if( current == 'left' ){
            current = 'right';
        }else{
            current = 'left';
        }
        z = 0;
    }else{
        z++;
    }
}

var seeds = { 'left' : [],
              'right' : [] };

var one = seedingSide(left.length);

for(var c=0 ; c < one.length ; c++){
    seeds.left.push(left[one[c]-1]);
    seeds.right.push(right[one[c]-1]);
}

function seedingSide(numPlayers){
  var rounds = Math.log(numPlayers)/Math.log(2)-1;
  var pls = [1,2];
  for(var i=0;i<rounds;i++){
    pls = nextLayer(pls);
  }
  return pls;
  function nextLayer(pls){
    var out=[];
    var length = pls.length*2+1;
    pls.forEach(function(d){
      out.push(d);
      out.push(length-d);
    });
    return out;
  }
}

/* Create Each Row */
for( var row = 1 ; row <= rowsNeeded ; row++ ) { 
    
    var colsNeeded = colPattern[(row-1)],
        rowspan = 1,
   ...