A table with a fixed (sticky) header
(Originally posted on https://dev.to/debadeepsen/a-table-with-a-fixed-sticky-header-54gm)
Often, we come across situations where we have a table
with lots of data in it. So when we scroll, the table header are hidden off screen, and soon we don't know what columns we're looking at. This problem can easily be addressed by wrapping the table
in a div
, and a bit of friendly CSS.
position: sticky
Sticky positioning is kind of a hybrid, between relative
and fixed
. To quote https://developer.mozilla.org/en-US/docs/Web/CSS/position, "The element is positioned according to the normal flow of the document, and then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor), including table-related elements, based on the values of top, right, bottom, and left." Basically, the element occurs in the normal document flow, until you scroll past a certain offset, at which point it sticks to the top of the specified container.
We're going to wrap our table
in a div
(which we'll make scrollable by setting its height
and overflow-y
properties), and make the th
s position in a sticky way. We'll also collapse the internal borders of the table using the border-collapse
property. Is it really that simple? It actually is.
Here's the code, in its full unadulterated glory (don't worry, I didn't include any spoiler from season 2 of The Umbrella Academy, but seriously, go watch it):
HTML
<!DOCTYPE html>
<html>
<head>
<title>Sticky Header</title>
<meta charset="UTF-8" />
<link rel="stylesheet" href="src/styles.css" />
</head>
<body>
<div class="wrapper">
<table>
<thead>
<tr>
<th>Number</th>
<th>Name</th>
<th>Superpower</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Luther</td>
<td>Super-strength</td>
<td>luther@umbrella.edu</td>
</tr>
<tr>
<td>2</td>
<td>Diego</td>
<td>Telekinesis</td>
<td>diego@umbrella.edu</td>
</tr>
<tr>
<td>3</td>
<td>Allison</td>
<td>Rumor</td>
<td>allison@umbrella.edu</td>
</tr>
<tr>
<td>4</td>
<td>Klaus</td>
<td>Seance</td>
<td>klaus@umbrella.edu</td>
</tr>
<tr>
<td>5</td>
<td>Five</td>
<td>Time-travel</td>
<td>five@umbrella.edu</td>
</tr>
<tr>
<td>6</td>
<td>Ben</td>
<td>Inter-dimensional monster</td>
<td>ben@umbrella.edu</td>
</tr>
<tr>
<td>7</td>
<td>Vanya</td>
<td>Apocalyptic destruction</td>
<td>vanya@umbrella.edu</td>
</tr>
<tr>
<td>-</td>
<td>Reginald</td>
<td>[Spoiler] powers</td>
<td>reginald@umbrella.edu</td>
</tr>
<tr>
<td>-</td>
<td>Pogo</td>
<td>Human communication</td>
<td>pogo@umbrella.edu</td>
</tr>
<tr>
<td>-</td>
<td>Cha-Cha</td>
<td>Ruthlessness</td>
<td>chacha@temps.comm</td>
</tr>
<tr>
<td>-</td>
<td>Hazel</td>
<td>Compassion</td>
<td>hazel@temps.comm</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
CSS
body {
font-family: "Segoe UI", sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
}
th,
td {
padding: 8px;
}
th {
text-align: left;
background: #eee;
position: sticky;
top: 0px;
}
.wrapper {
border: 1px solid #ddd;
width: 100%;
height: 300px;
overflow-y: auto;
}
You can see the above example running on CodeSandbox here - https://codesandbox.io/s/determined-buck-396hm
So long for now, and happy positioning!