loading...
Cover image for A table with a fixed (sticky) header

A table with a fixed (sticky) header

debadeepsen profile image debadeepsen ・2 min read

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 ths 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!

Posted on by:

debadeepsen profile

debadeepsen

@debadeepsen

Full-stack software engineer, experienced in .NET, PHP, Node JS, Angular, Vue, React, and React Native. Master's Degree in Computer Science with focus on HCI. Lover of coffee, videogames, and cats.

Discussion

pic
Editor guide