javascripthtmlcsshtml-tablefixed-header-tables

Sticky subheaders in a scrolling table with a fixed head


I'm trying to create a table with a fixed header, where the body scrolls under the head - which is fine, and there's lots of great examples out there.

The complication is that I want to be able to have sticky subheaders that scroll with the rest of the table, until they hit the table header, and then don't move until the rest of the section has scrolled underneath them, at which point they're replaced by the next sticky subheader (a little like the iphone address book). An example of how I need it to look: Getting a sticky header to "push up", like in Instagram's iPhone app using CSS and jQuery

The example above isn't done with a table, and i have a lot of tabular data I need to show, so it will need to be a table.

I've not been able to find an example of this working so far and everything I've tried has failed miserably. I've included a link to a jsfiddle example that doesn't have any fixed heads etc, as I thought it would avoid conflicts with other solutions: https://jsfiddle.net/q7zLhus0/

<table>
<thead>
    <th>A</th>
    <th>B</th>
    <th>C</th>
    <th>D</th>
    <th>E</th>
</thead>
<tbody>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 1</th>
    </tr>
    <tr>
        <td>1</td>
        <td>6</td>
        <td>3</td>
        <td>6</td>
        <td>2</td>

    </tr>
    <tr>
        <td>1</td>
        <td>5</td>
        <td>7</td>
        <td>2</td>
        <td>5</td>

    </tr>
    <tr>
        <td>S</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>6</td>

    </tr>
    <tr>
        <td>8</td>
        <td>5</td>
        <td>3</td>
        <td>7</td>
        <td>9</td>

    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 2</th>
    </tr>
    <tr>
        <td>A</td>
        <td>5</td>
        <td>3</td>
        <td>H</td>
        <td>D</td>
    </tr>
    <tr>
        <td>Q</td>
        <td>R</td>
        <td>T</td>
        <td>2</td>
        <td>3</td>
    </tr>
    <tr>
        <td>6</td>
        <td>4</td>
        <td>W</td>
        <td>2</td>
        <td>6</td>
    </tr>
    <tr>
        <td>5</td>
        <td>3</td>
        <td>W</td>
        <td>5</td>
        <td>6</td>
    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 3</th>
    </tr>
    <tr>
        <td>1</td>
        <td>9</td>
        <td>E</td>
        <td>3</td>
        <td>S</td>
    </tr>
    <tr>
        <td>T</td>
        <td>4</td>
        <td>D</td>
        <td>H</td>
        <td>S</td>
    </tr>
    <tr>
        <td>4</td>
        <td>S</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
    </tr>
    <tr>
        <td>1</td>
        <td>4</td>
        <td>R</td>
        <td>7</td>
        <td>S</td>
    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 4</th>
    </tr>
    <tr>
        <td>5</td>
        <td>D</td>
        <td>S</td>
        <td>6</td>
        <td>S</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>4</td>
        <td>5</td>
        <td>J</td>
    </tr>
    <tr>
        <td>6</td>
        <td>S</td>
        <td>D</td>
        <td>F</td>
        <td>3</td>
    </tr>
    <tr>
        <td>F</td>
        <td>L</td>
        <td>P</td>
        <td>T</td>
        <td>D</td>
    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 5</th>
    </tr>
    <tr>
        <td>5</td>
        <td>D</td>
        <td>S</td>
        <td>6</td>
        <td>S</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>4</td>
        <td>5</td>
        <td>J</td>
    </tr>
    <tr>
        <td>6</td>
        <td>S</td>
        <td>D</td>
        <td>F</td>
        <td>3</td>
    </tr>
    <tr>
        <td>F</td>
        <td>L</td>
        <td>P</td>
        <td>T</td>
        <td>D</td>
    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 6</th>
    </tr>
    <tr>
        <td>5</td>
        <td>D</td>
        <td>S</td>
        <td>6</td>
        <td>S</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>4</td>
        <td>5</td>
        <td>J</td>
    </tr>
    <tr>
        <td>6</td>
        <td>S</td>
        <td>D</td>
        <td>F</td>
        <td>3</td>
    </tr>
    <tr>
        <td>F</td>
        <td>L</td>
        <td>P</td>
        <td>T</td>
        <td>D</td>
    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 7</th>
    </tr>
    <tr>
        <td>5</td>
        <td>D</td>
        <td>S</td>
        <td>6</td>
        <td>S</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>4</td>
        <td>5</td>
        <td>J</td>
    </tr>
    <tr>
        <td>6</td>
        <td>S</td>
        <td>D</td>
        <td>F</td>
        <td>3</td>
    </tr>
    <tr>
        <td>F</td>
        <td>L</td>
        <td>P</td>
        <td>T</td>
        <td>D</td>
    </tr>
    <tr>
        <th class="subheader" scope="rowgroup" colspan="5">Data group 8</th>
    </tr>
    <tr>
        <td>5</td>
        <td>D</td>
        <td>S</td>
        <td>6</td>
        <td>S</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>4</td>
        <td>5</td>
        <td>J</td>
    </tr>
    <tr>
        <td>6</td>
        <td>S</td>
        <td>D</td>
        <td>F</td>
        <td>3</td>
    </tr>
    <tr>
        <td>F</td>
        <td>L</td>
        <td>P</td>
        <td>T</td>
        <td>D</td>
    </tr>
</tbody>

Any help would be greatly appreciated. This one has really stumped me.


Solution

  • Add This Function

    function stickyTitles(stickies) {
    
            var thisObj = this;
    
            thisObj.load = function () {
    
                stickies.each(function () {
    
                    var thisSticky = jQuery(this).append('<span class="test" />');
                    thisSticky.parent().height(thisSticky.outerHeight());
    
                    jQuery.data(thisSticky[0], 'pos', thisSticky.offset().top);
    
                });
    
                jQuery(window).off("scroll.stickies").on("scroll.stickies", function () {
    
                    thisObj.scroll();
    
                });
            }
    
            thisObj.scroll = function () {
    
                stickies.each(function (i) {
    
                    var thisSticky = jQuery(this),
                        nextSticky = stickies.eq(i + 1),
                        prevSticky = stickies.eq(i - 1),
                        pos = jQuery.data(thisSticky[0], 'pos');
    
                    if (pos <= jQuery(window).scrollTop()) {
    
                        thisSticky.addClass("fixed");
    
                        if (nextSticky.length > 0 && thisSticky.offset().top >= jQuery.data(nextSticky[0], 'pos') - thisSticky.outerHeight()) {
    
                            thisSticky.addClass("absolute").css("top", jQuery.data(nextSticky[0], 'pos') - thisSticky.outerHeight());
                        }
    
                    } else {
    
                        thisSticky.removeClass("fixed");
    
                        if (prevSticky.length > 0 && jQuery(window).scrollTop() <= jQuery.data(thisSticky[0], 'pos') - prevSticky.outerHeight()) {
    
                            prevSticky.removeClass("absolute").removeAttr("style");
                        }
                    }
                });
            }
        }
    
        jQuery(document).ready(function () {
    
            new stickyTitles(jQuery(".subheader")).load();
    
        });
    

    Demo Link -https://jsfiddle.net/kjo9w57a/1/