How to set tbody height with overflow scroll
If you want tbody
to show a scrollbar, set its display: block;
.
Set display: table;
for the tr
so that it keeps the behavior of a table.
To evenly spread the cells, use table-layout: fixed;
.
DEMO
CSS:
table, tr td {
border: 1px solid red
}
tbody {
display: block;
height: 50px;
overflow: auto;
}
thead, tbody tr {
display: table;
width: 100%;
table-layout: fixed;/* even columns width , fix width of table too*/
}
thead {
width: calc( 100% - 1em )/* scrollbar is average 1em/16px width, remove it from thead width */
}
table {
width: 400px;
}
If tbody
doesn't show a scroll, because content is less than height
or max-height
, set the scroll any time with: overflow-y: scroll;
. DEMO 2
<editS/updateS>
2019 - 04/2021
- Important note: this approach to making a table scrollable has drawbacks in some cases. (See comments below.) some of the duplicate answers in this thread deserves the same warning by the way
WARNING: this solution disconnects the thead and tbody cell grids; which means that in most practical cases, you will not have the cell alignment you expect from tables. Notice this solution uses a hack to keep them sort-of aligned: thead { width: calc( 100% - 1em ) }
Anyhow, to set a scrollbar, a display reset is needed to get rid of the table-layout (which will never show scrollbar).
Turning the
<table>
into a grid viadisplay:grid
/contents
will also leave a gap in between header and scrollable part, to mind about. (idem if built from divs)overflow:overlay;
has not yet shown up in Firefox ( keep watching it)position:sticky
will require a parent container which can be the scrolling one. make sure yourthead
can be sticky if you have a few rows androwspan/colspan
headers in it (it does not with chrome).
So far, there is no perfect solution yet via CSS only. there is a few average ways to choose along so it fits your own table (table-layout:fixed; is .. fixing table and column's width, but javascript could probably be used to reset those values => exit pure CSS)
Another approach is to wrap your table in a scrollable element and set the header cells to stick to the top.
The advantage of this approach is that you don't have to change the display on tbody and you can leave it to the browser to calculate column width while keeping the header cell widths in line with the data cell column widths.
/* Set a fixed scrollable wrapper */
.tableWrap {
height: 200px;
border: 2px solid black;
overflow: auto;
}
/* Set header to stick to the top of the container. */
thead tr th {
position: sticky;
top: 0;
}
/* If we use border,
we must use table-collapse to avoid
a slight movement of the header row */
table {
border-collapse: collapse;
}
/* Because we must set sticky on th,
we have to apply background styles here
rather than on thead */
th {
padding: 16px;
padding-left: 15px;
border-left: 1px dotted rgba(200, 209, 224, 0.6);
border-bottom: 1px solid #e8e8e8;
background: #ffc491;
text-align: left;
/* With border-collapse, we must use box-shadow or psuedo elements
for the header borders */
box-shadow: 0px 0px 0 2px #e8e8e8;
}
/* Basic Demo styling */
table {
width: 100%;
font-family: sans-serif;
}
table td {
padding: 16px;
}
tbody tr {
border-bottom: 2px solid #e8e8e8;
}
thead {
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
tbody tr:hover {
background: #e6f7ff;
}
<div class="tableWrap">
<table>
<thead>
<tr>
<th><span>Month</span></th>
<th>
<span>Event</span>
</th>
<th><span>Action</span></th>
</tr>
</thead>
<tbody>
<tr>
<td>January</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>February. An extra long string.</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>March</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>April</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>May</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>June</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>July</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>August</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>September</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>October</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>November</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
<tr>
<td>December</td>
<td>AAA</td>
<td><span>Invite | Delete</span></td>
</tr>
</tbody>
</table>
</div>
By default overflow
does not apply to table group elements unless you give a display:block
to <tbody>
also you have to give a position:relative
and display: block
to <thead>
. Check the DEMO.
.fixed {
width:350px;
table-layout: fixed;
border-collapse: collapse;
}
.fixed th {
text-decoration: underline;
}
.fixed th,
.fixed td {
padding: 5px;
text-align: left;
min-width: 200px;
}
.fixed thead {
background-color: red;
color: #fdfdfd;
}
.fixed thead tr {
display: block;
position: relative;
}
.fixed tbody {
display: block;
overflow: auto;
width: 100%;
height: 100px;
overflow-y: scroll;
overflow-x: hidden;
}
It is simple way to use scroll bar to table body
/* It is simple way to use scroll bar to table body*/
table tbody {
display: block;
max-height: 300px;
overflow-y: scroll;
}
table thead, table tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
<table>
<thead>
<th>Invoice Number</th>
<th>Purchaser</th>
<th>Invoice Amount</th>
<th>Invoice Date</th>
</thead>
<tbody>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
<tr>
<td>INV-1233</td>
<td>Dinesh Vaitage</td>
<td>$300</td>
<td>01/12/2017</td>
</tr>
</tbody>
</table>