Scrollable Table

Now we can get back to where we started and implement the scrollable table relatively easy. The problem now can be taken apart into three small problems. The first is to set up the HTML and CSS. The table actually consists of two tables. One for the header and one for the body. The tables are placed inside two containers where the header container has its scroll synchronized with the body. The HTML looks like this:

<div class="scrollTable" id="testScrollTable">
   <span class="scrollTableHead">
      <table cellspacing="0" frame="border">
      <tr>
         <td><nobr>Header One</nobr></td>
         <td><nobr>Header Two</nobr></td>
         <td><nobr>Header Three</nobr></td>
         <td><nobr>Header Foour</nobr></td>
         <td><nobr>Header Five</nobr></td>
         <td></td>
      </tr>
      </table>
   </span>
   <span class="scrollTableBody">
      <table cellspacing="0">

      <script>
         for (var i = 0; i < 50; i++)
            document.write("<tr><td nowrap>Some text</td>" +
            "<td nowrap>Something else</td><td nowrap>More</td>" +
            "<td nowrap>less</td><td nowrap>And last but not least</td></tr>");
      </script>
      </table>
   </span>
</div>

You should make sure that the header has one more column than the body. I've used a script to write the rows for the table but it could be done in the normal way. You should also set up the class names as in the HTML or you will not get the same look (if you want that look of course). The class and ids are not used in the script so there is nothing preventing you from using your own class and id names. The only thing is that if the CSS is not set up correctly (especially the overflow, width and height values) the scroll bars might not show up. To be able to force the width of the table cells in the header that table needs to have table-layout set to fixed as well. The entire style block looks like this:

.scrollTable {
   border-left: 1px solid buttonshadow;
   border-right: 1px solid buttonhighlight;
   border-top: 1px solid buttonshadow;
   border-bottom: 1px solid buttonhighlight;
   background: window;

   width: 100%;
   height: 100%;
   overflow: hidden
}

.scrollTableHead {
   behavior: url("syncscroll.htc");
   background: buttonface;
   width: 100%;
   overflow: hidden;
}

.scrollTableHead table {
   background: buttonface;
   empty-cells: show;
   table-layout: fixed;
}

.scrollTableHead table td {
   border-left: 1px solid buttonhighlight;
   border-right: 1px solid buttonshadow;
   border-top: 1px solid buttonhighlight;
   border-bottom: 1px solid buttonshadow;

}

.scrollTableHead td,
.scrollTableBody td {
   color: windowtext;
   font: icon;
   padding: 2px;
}

.scrollTableBody {
   overflow: auto;
   /* height needs to be calculated in a script */
   width: 100%;
}

Adding scroll synchronization

The second problem is to set up the scroll synchronization. This is easy now that we have the behavior. In the onload handler for the window we add the following:

window.attachEvent("onload", function () {
   var testElement = document.getElementById("testScrollTable")
   initScrollTable(testElement);
});

function initScrollTable(oElement) {
   resizeScrollTable(oElement);
   oElement.firstChild.syncTo = oElement.lastChild.uniqueID;
   oElement.firstChild.syncDirection = "horizontal";
}

Resizing the table

The third problem is (as you might have seen in the code above) to resize the child elements of the scroll table. We both need to set the height of the body table and synchronize the width of the table cells in the header with the widths of the columns in the body table. Setting the height of the table is simple and to update the width of the cells in the header we go through the cells in the first row of the body table and copy the values of the width to the cells in the header. There is also some code to set the width of the header to make it fill out the scroll table.

function resizeScrollTable(oElement) {
   var head = oElement.firstChild;
   var headTable = head.firstChild;
   var body = oElement.lastChild;
   var bodyTable = body.firstChild;
   
   body.style.height = Math.max(0, oElement.clientHeight - head.offsetHeight);
   
   var scrollBarWidth = body.offsetWidth - body.clientWidth;
   
   // set width of the table in the head
   headTable.style.width = Math.max(0, Math.max(bodyTable.offsetWidth + scrollBarWidth, oElement.clientWidth));

   // go through each cell in the head and resize
   var headCells = headTable.rows[0].cells;
   var bodyCells = bodyTable.rows[0].cells;
   
   for (var i = 0; i < bodyCells.length; i++)
      headCells[i].style.width = bodyCells[i].offsetWidth;
}

Demo

I've combined all this into simple demo. Try resizing the window to see how the scroll bars appear when needed. To view the complete source right click in the demo window or click here.

Synchronized Scroll
Demo without behavior
Behavior version
Behavior version demo
Scrollable Table
Scrollable Table Demo
Download this sample

Author: Erik Arvidsson