Bootstrap 3.0 - Table

HTML

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css">
<div class="custom-table">
  <div class="custom-table--fixed-wrapper">
    <div class="custom-table--header-wrapper">
      <table class = "table table-bordered">
        <tr>
          <th> Game ID </th>
        </tr>
      </table>  
    </div>

    <div class="custom-table--body-wrapper is-fixed" style="height: 300px;">
      <table class = "table table-hover table-bordered">
       <tr>
         <td> 1 </td>
       </tr>
       <tr>
         <td> 2 </td>
       </tr>
       <tr>
         <td> 13 </td>
        </tr>
        <tr>
         <td> 1 </td>
       </tr>
       <tr>
         <td> 2 </td>
       </tr>
       <tr>
         <td> 13 </td>
        </tr>
        <tr>
         <td> 1 </td>
       </tr>
       <tr>
         <td> 2 </td>
       </tr>
       <tr>
         <td> 13 </td>
        </tr>
        <tr>
         <td> 1 </td>
       </tr>
       <tr>
         <td> 2 </td>
       </tr>
       <tr>
         <td> 13 </td>
        </tr>
      </table>
    </div>
  </div>
  <div class="custom-table--header-wrapper">
    <table class = "table table-bordered">
      <tr>
        <th width="80"> Game ID </th>
        <th> Status </th>
        <th> Players </th>
        <th> Turn </th>
        <th> Last Turn </th>
        <th> Operations </th>
        <th class="gutter"></th>
      </tr>
    </table>  
  </div>

  <div class="custom-table--body-wrapper" style="height: 300px;">
    <table class = "table table-hover table-bordered">
     <tr>
       <td width="80"> 1 </td>
       <td> IN PROGRESS </td>
       <td> 4/4 </td>
       <td> tedbeem </td>
       <td> 11/12/13 6:30 PM </td>
       <td> <button class = "btn btn-primary"> View </button> </td>
     </tr>
     <tr>
       <td> 2...

CSS

body {
  padding: 10px;
}

.custom-table {
  position: relative;
}

/** 右侧边框 */
.custom-table::before {
  content: "";
  display: block;
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  border-right: 1px solid #ddd;
}

/** 底部边框 */
.custom-table::after {
  content: "";
  display: block;
  height: 0px;
  position: relative;
  top: -1px;
  border-bottom: 1px solid #ddd;
}

.custom-table .table {
  table-layout: fixed;
  margin-bottom: 0;
}

/** Header 右侧的空隙 */
.custom-table th.gutter {
  width: 15px;
  padding: 0;
}

.custom-table--body-wrapper {
  overflow: auto;
  margin-top: -1px;
}

.custom-table--body-wrapper.is-fixed {
  overflow-y: hidden;
}

.custom-table--fixed-wrapper {
  box-shadow:4px 0px 4px rgba(0, 0, 0, 0.1);
  position: absolute; 
  left: 0;
  top: 0;
  bottom: 0;
  width: 81px;
  background-color: #fff;
}

.custom-table td, .custom-table th {
  white-space: nowrap;
  overflow: hidden;
  height: 42px;
  padding: 2px !important;
}

.custom-table tbody > tr.hover > td {
  background-color: #f5f5f5;
}

Babel + JSX

// 同步两边的滚动
$('.custom-table--body-wrapper').on('scroll', function(event) {
	var scrollTop = $(this).prop('scrollTop');
  $('.custom-table--body-wrapper.is-fixed').prop('scrollTop', scrollTop);
});

var getRowIndex = function(event) {
  var target = event.target;
  if (target.tagName === 'TR') {
    return $(target).index();
  } else {
  	return $(event.target).parent('tr').index();
  }
};

// 同步两边的 hover 效果
$('.custom-table--body-wrapper tr').hover(function(event) {
  var index = getRowIndex(event);
	$('.custom-table--body-wrapper tr:nth-child(' + (index + 1) + ')').addClass('hover');
}, function(event) {
	var index = getRowIndex(event);
	$('.custom-table--body-wrapper tr:nth-child(' + (index + 1) + ')').removeClass('hover');
});