How to place the dataTables' horizontal scrollbar on top of the table?
Asked Answered
T

5

11

I have a really large datatable and I want to put the horizontal scrollbar on top as well as on the bottom of the table so it would be easier for the user to scroll (the datatable has a lot of columns). Is there an easy and proper way to achieve this?

Truckage answered 2/2, 2016 at 7:1 Comment(0)
S
25

You can use a container that has a maximum width and put the table inside.

<div class="large-table-container-1">
  <table>...</table>
</div>

Depending on how much reliability you want, you can make:

A. Bottom scrollbar, just set a maximum width and overflow x to scroll:

.large-table-container-1 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}

Demo:

.large-table-container-1 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-container-1 table {
  
}

/*misc*/
td {
  border: 1px solid gray;
}

th {
  text-align: left;
}
<div class="large-table-container-1">
  <table>
    <thead>
      <tr>
        <th colspan="20">
          Bottom scrollbar:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
      </tr>
    </tbody>
  </table>
</div>

B. Top scrollbar, a little hacky, use a 180 degree transform to rotate the scrollbar to the top, then again another 180 degree to put back the content.

.large-table-container-2 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
  transform:rotateX(180deg);
}

.large-table-container-2 table {
  transform:rotateX(180deg);
}

You may want to use broswser specific prefixes for transform, like -webkit-transform:rotateX(180deg);.

Demo:

.large-table-container-2 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
  transform:rotateX(180deg);
}
.large-table-container-2 table {
  transform:rotateX(180deg);
}

/*misc*/
td {
  border: 1px solid gray;
}

th {
  text-align: left;
}
<div class="large-table-container-2">
  <table>
    <thead>
      <tr>
        <th colspan="20">
          Top scrollbar:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
      </tr>
    </tbody>
  </table>
</div>

C. Top and bottom scrollbar, a little more hacky. Needs some javascript. Use the solution form A above and add a 'fake' div for top scrollbar:

<div class="large-table-fake-top-scroll-container-3">
  <div>&nbsp;</div>
</div>
<div class="large-table-container-3">
  <table>...</table>
</div>


.large-table-container-3 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-container-3 table {

}
.large-table-fake-top-scroll-container-3 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-fake-top-scroll-container-3 div {
  background-color: red;/*Just for test, to see the 'fake' div*/
  font-size:1px;
  line-height:1px;
}

And a little javascript to catch the scroll on the top fake div and then scroll the table container (and vice-versa), with jQuery:

$(function() {
  var tableContainer = $(".large-table-container-3");
  var table = $(".large-table-container-3 table");
  var fakeContainer = $(".large-table-fake-top-scroll-container-3");
  var fakeDiv = $(".large-table-fake-top-scroll-container-3 div");

  var tableWidth = table.width();
  fakeDiv.width(tableWidth);

  fakeContainer.scroll(function() {
tableContainer.scrollLeft(fakeContainer.scrollLeft());
  });
})

Demo:

$(function() {
  var tableContainer = $(".large-table-container-3");
  var table = $(".large-table-container-3 table");
  var fakeContainer = $(".large-table-fake-top-scroll-container-3");
  var fakeDiv = $(".large-table-fake-top-scroll-container-3 div");

  var tableWidth = table.width();
  fakeDiv.width(tableWidth);
  
  fakeContainer.scroll(function() {
    tableContainer.scrollLeft(fakeContainer.scrollLeft());
  });
  tableContainer.scroll(function() {
    fakeContainer.scrollLeft(tableContainer.scrollLeft());
  });
})
.large-table-container-3 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-container-3 table {
  
}
.large-table-fake-top-scroll-container-3 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-fake-top-scroll-container-3 div {
  background-color: red;
  font-size:1px;
  line-height:1px;
}

/*misc*/
td {
  border: 1px solid gray;
}

th {
  text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="large-table-fake-top-scroll-container-3">
  <div>&nbsp;</div>
</div>
<div class="large-table-container-3">
  <table>
    <thead>
      <tr>
        <th colspan="20">
          Top and bottom scrollbar:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
      </tr>
    </tbody>
  </table>
</div>

The working complete code for all three solutions:

$(function() {
  var tableContainer = $(".large-table-container-3");
  var table = $(".large-table-container-3 table");
  var fakeContainer = $(".large-table-fake-top-scroll-container-3");
  var fakeDiv = $(".large-table-fake-top-scroll-container-3 div");

  var tableWidth = table.width();
  fakeDiv.width(tableWidth);
  
  fakeContainer.scroll(function() {
    tableContainer.scrollLeft(fakeContainer.scrollLeft());
  });
  tableContainer.scroll(function() {
    fakeContainer.scrollLeft(tableContainer.scrollLeft());
  });
})
/*Bottom scrollbar*/
.large-table-container-1 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-container-1 table {
  
}

/*Top scrollbar*/
.large-table-container-2 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
  transform:rotateX(180deg);
}
.large-table-container-2 table {
  transform:rotateX(180deg);
}

/*Top and bottom scrollbar*/
.large-table-container-3 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-container-3 table {
  
}
.large-table-fake-top-scroll-container-3 {
  max-width: 200px;
  overflow-x: scroll;
  overflow-y: auto;
}
.large-table-fake-top-scroll-container-3 div {
  background-color: red;
  font-size:1px;
  line-height:1px;
}

/*misc*/
td {
  border: 1px solid gray;
}

th {
  text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="large-table-container-1">
  <table>
    <thead>
      <tr>
        <th colspan="20">
          Bottom scrollbar:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
      </tr>
    </tbody>
  </table>
</div>

<div class="large-table-container-2">
  <table>
    <thead>
      <tr>
        <th colspan="20">
          Top scrollbar:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
      </tr>
    </tbody>
  </table>
</div>


<div class="large-table-fake-top-scroll-container-3">
  <div>&nbsp;</div>
</div>
<div class="large-table-container-3">
  <table>
    <thead>
      <tr>
        <th colspan="20">
          Top and bottom scrollbar:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
        <td>00</td>
        <td>01</td>
        <td>02</td>
        <td>03</td>
        <td>04</td>
        <td>05</td>
        <td>06</td>
        <td>07</td>
        <td>08</td>
        <td>09</td>
      </tr>
    </tbody>
  </table>
</div>
Saberio answered 2/2, 2016 at 8:44 Comment(2)
Excellent answer with many approaches! I like it! However, fakeContainer.scroll() calls the other containers scroll(), which calls fakeContainer's scroll(), which creates an infinite loop, and I can no longer scroll long distances. I have a graphic of the problem and a solution here: https://mcmap.net/q/125515/-horizontal-scrollbar-on-top-and-bottom-of-table Still upvoting, because A and B approaches are flawless!Trubow
Amazing answer! I had to massage my solution a little to this: var tableContainer = $(".dataTables_scrollBody"); using DataTables 1.10.20Beals
T
5

I found the solution to put scroll on top of table. Have look please: Demo in Fiddle Hope it would help.

    `.dataTables_scrollBody {
        transform:rotateX(180deg);
    }
    .dataTables_scrollBody table {
        transform:rotateX(180deg);
    }`

    $(document).ready(function() {
    $('#example').DataTable( {
            scrollX : 'TRUE',
        initComplete: function () {
            this.api().columns().every( function () {
                var column = this;
                var select = $('<select><option value=""></option></select>')
                    .appendTo( $(column.footer()).empty() )
                    .on( 'change', function () {
                        var val = $.fn.dataTable.util.escapeRegex(
                            $(this).val()
                        );

                        column
                            .search( val ? '^'+val+'$' : '', true, false )
                            .draw();
                    } );

                column.data().unique().sort().each( function ( d, j ) {
                    select.append( '<option value="'+d+'">'+d+'</option>' )
                } );
            } );
        }
    } );
    $('#example tfoot tr').insertAfter($('#example thead tr'));
} );
Terpstra answered 13/9, 2018 at 9:55 Comment(2)
Actually datatable is generating on html too. i wrote css code it will rotate table with html at 180(degree). Now table data and complete table will show in opposite direction. Than i just rotate inner table again now table is at fixed position and your scroll bar would be on top. For more have look to the FIDDLE link.Terpstra
where should I add class "dataTables_scrollBody"?Trough
S
5

I show scrollbar of the header with css/jQuery and set the body scrollLeft to the header's scroll left.

Example:

// Put top scroller
$('.dataTables_scrollHead').css({
    'overflow-x':'scroll'
}).on('scroll', function(e){
    var scrollBody = $(this).parent().find('.dataTables_scrollBody').get(0);
    scrollBody.scrollLeft = this.scrollLeft;
    $(scrollBody).trigger('scroll');
});
Stace answered 15/5, 2019 at 15:37 Comment(1)
this is working perfectly without changing any codeInobservance
A
0

pls have a look at a similar query here:

horizontal scrollbar on top and bottom of table

This solution has worked for my datatable.

Antitrust answered 2/2, 2016 at 7:38 Comment(2)
I cannot access the ID of the bottom scrollbar because it has been automatically added by datatablesTruckage
Link-only answers are not considered valuable on SO.Tullis
A
-3

You can use overflow property in css.

You should separate body and header of your table in two different tables. then place the second table (body of original table) in a div and use overflow on this div.

DEMO in jsfiddle

<html>
<head>
    <style>
        .myOverflow {
            height: 100px; 
            overflow-y: scroll; 
            display: inline-block;
        }
    </style>
</head>
<body>
    <table id="HeaderTable">
        <tr>
            <td class="col1">Column1</td>
            <td class="col2">Column2</td>
        </tr>
    </table>
    <div class="myOverflow">
        <table id="BodyTable">
            <tr>
                <td class="col1">a</td>
                <td class="col2">b</td>
            </tr>
            <tr>
                <td>c</td>
                <td>d</td>
            </tr>
            <tr>
                <td>e</td>
                <td>f</td>
            </tr>
        </table>
    </div>
</body>
</html>

<script>
</script>
Allenaallenby answered 2/2, 2016 at 7:19 Comment(3)
This did not work, nothing appeared on top of my tableTruckage
I changed my answer, please check the fiddle for demo.Allenaallenby
This is a neat idea, Emad Armoun. But I think the OP was asking for a scrollbar on the top, while it seems you have put the header on the top and the scrollbar on the side. Your code is neat, but, not sure it'll work here.Trubow

© 2022 - 2024 — McMap. All rights reserved.