Long Table Scroll

Uses jQuery to maniuplate the DOM for tables with class="body_scroll" so that the table's body will appear to be scrollable.

by Jeromy French

HTML

<table class="body_scroll">
    <caption>Wide Table</caption>
    <thead>
        <tr>
            <th>Really Long Column Name To Show Alignment</th>
            <th>Number</th>
            <th>Age</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <td colspan="3">Footers are table elements too!</td>
        </tr>
    </tfoot>
    <tbody>
        <tr>
            <td>John</td>
            <td>2131</td>
            <td>12</td>
        </tr>
        <tr>
            <td>Stacy</td>
            <td>4123</td>
            <td>5</td>
        </tr>
        <tr>
            <td>Chris</td>
            <td>122</td>
            <td>7</td>
        </tr>
        <tr>
            <td>John</td>
            <td>2131</td>
            <td>12</td>
        </tr>
        <tr>
            <td>Stacy</td>
            <td>4123</td>
            <td>5</td>
        </tr>
        <tr>
            <td>Chris</td>
            <td>122</td>
            <td>7</td>
        </tr>
        <tr>
            <td>John</td>
            <td>2131</td>
            <td>12</td>
        </tr>
        <tr>
            <td>Stacy</td>
            <td>4123</td>
            <td>5</td>
        </tr>
        <tr>
            <td>Chris</td>
            <td>122</td>
            <td>7</td>
        </tr>
        <tr>
            <td>John</td>
            <td>2131</td>
            <td>12</td>
        </tr>
        <tr>
            <td>Stacy</td>
            <td>4123</td>
            <td>5</td>
        </tr>
        <tr>
            <td>Chris</td>
            <td>122</td>
            <td>7</td>
        </tr>
    </tbody>
</table>

<hr />
<table class="body_scroll">
    <caption>Medium Table</caption>
    <thead>
        <tr>
            <th>Smaller size</th>
            <th>Number</th>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>John</td>
            <td>4565646464645646457</td>
            <td>8564</td>
        </tr>
        <tr>
            <td>Stacy</td>
 ...

CSS

/*necessary for scroll*/
div.body_scroll {
    height: 120px;
    overflow-y: auto; 
}

/*everything that follows is just to help the eye identify the table elements*/
table caption {
    color:blue;
    font-weight:bold;
    text-align:center;
}

table tfoot, .table_footer {
    color:orange;
}

table thead th {
    font-weight:bold;
}

th, td {
    padding:2px;
}

JavaScript

window.setTimeout(function(){
    confirm('check out how our page looks before we inject the scrolling feature')
if ( $('table.body_scroll').length ) {
    var $table_body_scroll=$('table.body_scroll'),
        header_table=$( '<table aria-hidden="true" class="header_table"><thead><tr><td></td></tr></thead></table>' ),
        scroll_div='<div class="body_scroll"></div>';
        
    //inject table that will hold stationary row header; inject the div that will get scrolled
    $table_body_scroll.before( header_table ).before( scroll_div );
    
    $table_body_scroll.each(function (index) {
        //to minimize FUOC, I like to set the relevant variables before manipulating the DOM
        var columnWidths = [];
        var $targetDataTable=$(this);
        var $targetHeaderTable=$("table.header_table").eq(index);
        var $targetDataTableFooter=$targetDataTable.find('tfoot');
        
        // Get column widths
        $($targetDataTable).find('thead tr th').each(function (index) {
            columnWidths[index] = $(this).width();
        });
        
        //place target table inside of relevant scrollable div (using jQuery eq() and index)
        $('div.body_scroll').eq(index).prepend( $targetDataTable ).width( $($targetDataTable).width()+25 );
        
        // hide original caption, header, and footer from sighted users
        $($targetDataTable).children('caption, thead, tfoot').hide();
        
        // insert header data into static table
        $($targetHeaderTable).find('thead').replaceWith( $( $targetDataTable ).children('caption, thead').clone().show() );
        
        // modify column width for header
        $($targetHeaderTable).find('thead tr th').each(function (index) {
            $(this).css('width', columnWidths[index]);
        });
        
        // make sure table data still lines up correctly
        $($targetDataTable).find('tbody tr:first td').each(function (index) {
            $(this).css('width',...